Re: vtbl inheritance
On 2011-01-31 09:43:33 -0500, Leigh Johnston said:
On 31/01/2011 11:47, James Kanze wrote:
On Jan 30, 4:29 pm, Leigh Johnston<le...@i42.co.uk> wrote:
On 30/01/2011 16:14, Serve Laurijssen wrote:
Consider this code:
class RefCounted {
private: long m_nRefCount;
public: virtual ~RefCounted();
};
struct Header {
short us;
int i1;
int i2;
};
struct UnitHeader: public Header {
BYTE filler[sizeof(ULONG) - (sizeof(UnitHeader)& (sizeof(ULONG) - 1))];
};
class CHeader : public UnitHeader, public RefCounted {
};
RefCounted has a virtual destructor, UnitHeader and Header are POD structs.
CHeader inherits from UnitHeader and RefCounted.
Now consider this:
void CHeader::MakeDummy() {
memset((UnitHeader*)this, 0, sizeof(UnitHeader));
}
The 'this' pointer in CHeader is casted to UnitHeader struct and that
memory area set to zero.
But since the class inherits from a class with a virtual destructor Im
not sure this works. How does MSVC(2005) handle the Vtbl when inheriting
from a class with a vtbl?
That should work yes as you are calling memset on a POD base sub-object
(of type UnitHeader).
I don't think it will fail in this particular case, because of
the data types involved and their respective alignment
requirements. But in general, the actual number of bytes
occupied by UnitHeader may be less than sizeof(UnitHeader) when
UnitHeader is a base class, so brutally writing
sizeof(UnitHeader) bytes is not a safe operation. (The "empty
base class optimization" is somewhat miss-named, because it
doesn't apply to only empty base classes.)
What is this nonsense? A base subobject is an object and in this case
the object is POD and it is fine to memset a POD object with sizeof(POD
object type) bytes.
struct S { };
struct T : S { int i; };
T t;
Clause 9 [classes]/3: "Complete objects and *member* subobjects of
class type shall have nonzero size" [emphasis added]. So sizeof(S) is
required to be at least 1. But when S is used as a base class of T the
resulting subobject is neither a complete object nor a member subobjct,
so it is not required to have nonzero size. That's the "empty base
class optimization". It allows objects of type T to occupy sizeof(int)
bytes, with the S subobject taking up no space. If the compiler does
that, calling memset((S*)&t, '\0', sizeof(S)) will write 1 byte into t,
which will overwrite one of the bytes of t's int member.
--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)