I read somewhere that non-virtual non-static member functions do not add to the size of a class object, but can someone tell me where they are stored in memory. Static members functions, which also do not add to the size of a class object, are stored in static data segment, correct?
This cites the following example that I do not think is correct. Why is the size of Bbase 12- should not it be 8 (4 bytes for iMem (overrides base class imem) and one vptr)?
Also, should not sizeof (ABCDerived) be 20 (if iMem do not override then 16 bytes for iMem and 4 for vptr)?
---
class ABase{
int iMem;
};
class BBase : public virtual ABase {
int iMem;
};
class CBase : public virtual ABase {
int iMem;
};
class ABCDerived : public BBase, public CBase {
int iMem;
};
And if you check the size of these classes, it will be:
* Size of ABase : 4
* Size of BBase : 12
* Size of CBase : 12
* Size of ABCDerived : 24
--
Why is the size of Bbase 12- should not it be 8 (4 bytes for iMem (overrides base class imem) and one vptr)?
The BBase's iMem member variable is different from ABase's iMem member variable.
Be careful about claims that an object's size will be some specific value. Unless a particular compiler is named with a given configuration and platform, the size may actually be different from what is reasoned out as it is ultimately implementation defined.
C + C++ Compiler: MinGW port of GCC
Build + Version Control System: SCons + Bazaar
How a compiler handles all of these things is implementation defined. All of the answers you've been given is highly dependent on the compiler implementation.
Read what laserlight wrote in his post:
Be careful about claims that an object's size will be some specific value. Unless a particular compiler is named with a given configuration and platform, the size may actually be different from what is reasoned out as it is ultimately implementation defined.
does anyone know why it should not be 1 vptr but 2?
Does this example help?
Code:
#include <iostream>
using namespace std;
struct Automobile
{
virtual int GetNumberOfSeats(void) const = 0;
};
struct Sedan : virtual public Automobile
{
virtual int GetNumberOfSeats(void) const { return 6; }
};
struct Pickup : virtual public Automobile
{
virtual int GetNumberOfSeats(void) const { return 3; }
};
// see <http://en.wikipedia.org/wiki/Chevrolet_El_Camino>
struct ChevyElCamino : public Sedan, public Pickup
{
virtual int GetNumberOfSeats(void) const
{
return static_cast<Pickup>(*this).GetNumberOfSeats();
};
};
void main(void)
{
ChevyElCamino automobile;
cout << automobile.GetNumberOfSeats() << endl;
Automobile * pAuto = &automobile;
Sedan * pSedan = &automobile;
Pickup * pPickup = &automobile;
cout << *reinterpret_cast<int *>(&pAuto ) << endl;
cout << *reinterpret_cast<int *>(&pSedan ) << endl;
cout << *reinterpret_cast<int *>(&pPickup) << endl;
char c;
cin >> c;
}
When I run this, I get
3
4061396
4061388
4061392
I'm using MS VC++ on a 64 bit machine, but I assume gcc uses the same strategies. When this casts the automobile object to its different base-classes, the address returned is the address of the v-table pointer for the specific parent object (in this case three such pointers exist).
The reason there are two (or three) instead of one has to do with the way multiple inheritance works. You have told the compiler to include all the functionality from the Sedan and Pickup classes (i.e. the BBase and CBase classes). In this example, the differing functionality offered by the member functions makes more clear that the inherited functionality is indeed overriding the Automobile class, but the Pickup class and the Sedan class do not override each-other. Both must be present in the ElCamino class. That's why there are two v-table pointers. The compiler relies on you in the ElCamino or ABCDerived class to disambiguate (via casting) which parent object you really want to use at any point.
Last edited by GeoRanger; February 21st, 2010 at 11:20 PM.
Reason: fix problem with indirection in reinterpret_cast
With MS VC++, the decreased size is because the ABase v-table pointer is moved out of ABCDerived as ABase (including its v-table pointer) is reunitied (as two copies) with BBase and CBase.
The previous cautions by Paul McKenzie and laserlight deserve emphasis. Perhaps you might be able to expect the discussed behavior for any COM-compliant compiler, but it would be bad programming practice to write code dependent on this behavior. Apart from curiosity and learning exercises, if you see sizeof() used on a class which has a v-table, this is normally an automatic red flag that something's fishy. (There are some exceptions to this generalization which have to do with things like placement new, but I only mention that here because I know someone challenge the generalization if I don't.)
Last edited by GeoRanger; February 22nd, 2010 at 11:22 PM.
Reason: clarify sentence about exception to generalization
Bookmarks