12

this is kind of homework question. For the following code,

#include <iostream>
using namespace std;

class A
{
public:
    virtual void f(){}
};

class B
{
public:
    virtual void f2(){}
};

class C: public A, public B
{
public: 
    virtual void f3(){}
};

class D: public C
{
public:
    virtual void f4(){}
};

int main()
{
    cout<<sizeof(D)<<endl;
}

The output is: 8

Could anyone please explain how it is 8 bytes? If the vtable implementation is compiler dependent, what should I answer for this kind of question in interviews? What about virtual base classes?

EDIT: i am working on a 32-bit platform.

jogojapan
  • 68,383
  • 11
  • 101
  • 131
bjskishore123
  • 6,144
  • 9
  • 44
  • 66
  • 1
    The `sizeof` operator isn't really meaningful for class types in most scenarios. If you're relying on the size of a class for something, odds are good (though not 100%) that your design has gone wrong somewhere. Can you elaborate on what you're trying to accomplish in your homework, or is this the actual homework question? (If it's the latter and the instructor has not specified a particular compiler or platform, then the only correct answer is "the size of the class is an implementation detail.") – Jonathan Grynspan Jan 22 '11 at 05:46
  • @Jonathan: I faced this question in written test long ago, there was no such option like "implementation dependent" in multiple choices given. Company name is Phil***. I think, i can't mention company name here :) – bjskishore123 Jan 22 '11 at 05:55
  • Well then the written test was disallowing the correct answer. That doesn't make it incorrect. Neither "8 bytes" nor "two pointers" nor "64 bits" is the right answer, even if it is accurate on a particular system/compiler combination. – Jonathan Grynspan Jan 22 '11 at 06:08
  • 2
    If someone asks something like this in an interview question you might consider just responding with, "Thanks for your time, but I just decided I don't want to work here." – Edward Strange Jan 22 '11 at 07:05

4 Answers4

17

This is of course implementation-dependent. And it would make a terrible interview question. A good C++ programmer can just trust sizeof to be right and let the compiler worry about those vtable things.

But what's going on here is that a typical vtable-based implementation needs two vtables in objects of class C or D. Each base class needs its own vtable. The new virtual methods added by C and D can be handled by extending the vtable format from one base class, but the vtables used by A and B can't be combined.

In pseudo-C-code, here's how a most derived object of type D looks on my implementation (g++ 4.4.5 Linux x86):

void* D_vtable_part1[] = { (void*) 0, &D_typeinfo, &A::f1, &C::f3, &D::f4 };
void* D_vtable_part2[] = { (void*) -4, &D_typeinfo, &B::f2 };

struct D {
  void** vtable_A;
  void** vtable_B;
};

D d = { D_vtable_part1 + 1, D_vtable_part2 + 1 };
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • 1
    I don't consider it a terrible interview question. It will clearly shows whether the candidate knows, or not, what is going on under the hood. I would likewise ask questions about hardware (processor / cache / RAM etc) just to know the extent of the knowledge of the person I am willing to recruit. While it may not be necessary for day-to-day tasks, knowledge is never wasted. – Matthieu M. Jan 22 '11 at 11:21
4

In this question if you try to get Sizeof class A, it will give you answer '4' because A have only one virtual function so its __vptr will be of '4' byte.

In the same way, if you try to get Sizeof class B, it will give you answer '4' because B also have only one virtual function so its __vptr will be of '4' byte.

But class C is inheriting both classes A & B and C itself have a virtual function. So C will receive 2 __vptr pointers, and for its own virtual function C will use the inherited __vptr. So if you try to get Sizeof class C, it will give you answer '8' because C have two virtual pointers.

And lastly class D is inheriting class C so D will use inherited __vptr for its own virtual function and because class C have sizeof '8' byte so sizeof D will give you answer '8' byte.

BenMorel
  • 34,448
  • 50
  • 182
  • 322
iPhoneBuddy
  • 49
  • 10
1

Forgive me for being vague, but you are mentioning that it is homework in nature.

See what sizeof() returns for the other classes. Your answer will vary depending on your compiler and whether you are in a 32 or 64 bit environment.

Happy sleuthing!

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
-2

The size of the object has nothing to do with how many methods that it has, nor with whether those methods are virtual or not. The size of an object is determined solely by its member variables.

I can't tell you exactly why you're getting a size of 8 bytes. Since there are no data members in your class, a C++ compiler could in principle generate a class that occupies no space at all [1]! I'm guessing that the 8 bytes is the minimum required to provide a pointer to the vtbl, plus possibly some padding.

[1] I think. No time to check the spec to find out at the moment whether sizeof can ever return 0.

JSBձոգչ
  • 40,684
  • 18
  • 101
  • 169
  • @JSBangs: As am working on 32-bit platform, vptr takes 4 bytes. – bjskishore123 Jan 22 '11 at 05:30
  • @JSBangs: `sizeof` never returns zero, but a base class subobject can occupy zero bytes. – aschepler Jan 22 '11 at 05:34
  • 1
    @JSBangs @bjskishore123: The size of a `D` is 8 bytes because it contains *two* vtable 32-bit pointers. There's two because of the fact that class `D` derives from class `C` which derives from two different classes with virtual functions: class `A` and `B`. The presence of virtual functions requires at least one pointer to a vtable in the object in just about every C++ implementation. That's how polymorphism is implemented. – In silico Jan 22 '11 at 05:36
  • 5
    @JSBangs: "The size of an object is determined solely by its member variables." I'm sorry to say but that's not entirely correct. The size of an object is determined by its member variables *and* the padding *and* the presence of virtual functions or bases. – In silico Jan 22 '11 at 05:41
  • @In silico: right, For class C, does it insert f3 in the both vtables inherited from A, B? If not, C should have one more vtable making its size 12 bytes. – bjskishore123 Jan 22 '11 at 05:45
  • @bjskishore123: Multiple vtable pointers are needed only for classes using multiple inheritance of classes with virtual functions. If a given class inherits from only one class that has at least one virtual function (so classes that do not have virtual functions don't count), then there will be only one vtable pointer. – In silico Jan 22 '11 at 05:48
  • @In silico: Correct,u can write this as answer, i shall upvote it :) – bjskishore123 Jan 22 '11 at 05:50
  • @bjskishore123: Thanks, but aschepler's answer conveys what I just said in a more concise manner. :-) – In silico Jan 22 '11 at 05:51
  • @In silico: Thank you, you are also great :) – bjskishore123 Jan 22 '11 at 05:53