March 26, 2005
Virtual sizeof
Do you ever wish you could do this:
class Base
{
};
class Derived: public Base
{
int x;
};
Base *p = new Derived;
size_t s = sizeof(*p); // s is sizeof(Derived)
Of course it doesn't work because s becomes the size of Base rather than Derived. What you really want is a kind of "virtual sizeof". This is what I came up with:class Base
{
public:
virtual size_t Size() const = 0;
};
class Derived: public Base
{
int x;
};
template < typename T >
class Wrapper: public T
{
public
virtual size_t Size() const
{
return sizeof(T);
}
};
template < typename T >
T *New()
{
return new Wrapper< T >;
}
Base *p = New<Derived>();
size_t s = p->Size(); // works as desired
Comments:
<< Home
I'd been troubled by this ever since I first read about it, for the simple fact that it's "extra stuff to remember." E.g. if you try MyThing* mt = new MyThing, you get compile errors that won't make it obvious what to do.
However, this morning I realized a solution that works for my own mad interpretation of The Right Thing.
template < class T >
T* Create()
{
return new Wrapper< T >;
}
and then, you make the ctors protected, and ding-dong, you're set.
So, you now have MyThing* mt = Create< MyThing >();, and voila. Sure this is a bit boilerplatey as well, but the user doesn't need to worry about the Wrapper class at all in this case, they just directly say "create this actual thing that I want, and don't worry that it's giving me a derived class in its stead."
(Some compilers will mis-link the function signature that I gave above, unfortunately. For those, change it to T* Create(T* =0).)
However, this morning I realized a solution that works for my own mad interpretation of The Right Thing.
template < class T >
T* Create()
{
return new Wrapper< T >;
}
and then, you make the ctors protected, and ding-dong, you're set.
So, you now have MyThing* mt = Create< MyThing >();, and voila. Sure this is a bit boilerplatey as well, but the user doesn't need to worry about the Wrapper class at all in this case, they just directly say "create this actual thing that I want, and don't worry that it's giving me a derived class in its stead."
(Some compilers will mis-link the function signature that I gave above, unfortunately. For those, change it to T* Create(T* =0).)
Ugh, now I see that's what you were getting at with the New template function. Doh! That'll teach me not to read the post for weeks before posting my own tidbit.
Still- as I said the boilerplate or "misdirection" as it were still rubs me the wrong way somewhat. I'd prefer something like MyThing* mt = MyThing::Create();, but that too requires support in the class itself which you're explicitly looking to avoid.
Myself, maybe I'd make a macro that said DECLARE_THE_JUNK, and was defined to provide bodies for those functions as appropriate. Despite all of the times I've done that, though, it too sits uneasily with me...
Post a Comment
Still- as I said the boilerplate or "misdirection" as it were still rubs me the wrong way somewhat. I'd prefer something like MyThing* mt = MyThing::Create();, but that too requires support in the class itself which you're explicitly looking to avoid.
Myself, maybe I'd make a macro that said DECLARE_THE_JUNK, and was defined to provide bodies for those functions as appropriate. Despite all of the times I've done that, though, it too sits uneasily with me...
<< Home