Reputation: 417
I have some understanding issues with following code segment and the output. Can anybody provide an explanation mainly why test() works the way as seen in output. I am using MSCV 2008 C++ Compiler.
class AS
{
int a;
public:
AS():a(1){show();}
virtual void show() {cout<<a<<endl;}
void test() { cout<<"Calling show()"<<endl; this->show();}
};
class BS: virtual public AS
{
int b;
public:
BS():b(2){show();}
virtual void show() {cout<<b<<endl;}
void test() { cout<<"Calling show()"<<endl; this->show();}
};
class CS:public virtual AS
{
int c;
public:
CS():c(3){show();}
virtual void show() {cout<<c<<endl;}
void test() { cout<<"Calling show()"<<endl; this->show();}
};
class DS:BS, public CS
{
int d;
public:
DS():d(4){show();}
virtual void show() {cout<<d<<endl;}
void test() { cout<<"Calling show()"<<endl; this->show();}
};
int main()
{
cout<<"Class Sizes:"<<endl;
cout<<sizeof(AS)<<endl;
cout<<sizeof(BS)<<endl;
cout<<sizeof(CS)<<endl;
cout<<sizeof(DS)<<endl;
AS* aa = new DS();
aa->test();
aa->show();
delete aa;
return 0;
}
Output is:-
Class Sizes:
8
20
20
32
1
2
3
4
Calling show()
4
4
and an breakpoint exception on deleting aa; Why ?
Upvotes: 1
Views: 160
Reputation: 2092
Here is my bit, pls correct me if I'm wrong.
[Note: vptr-vtable mechanism is used to implement virtual function calls and vbptr (virtual base class pointer) is used to implement virtual base class. Also, the sizeOf(of some polymorphic class) may vary based on compiler + platform being used]
1) An instance of class AS would need 8 bytes (4 bytes for "int a" + 4 bytes for hidden vptr) = 8
2) An instance of class BS would need 20 bytes
(4 bytes to hold base class AS + 4 bytes padding + 4 bytes for "int b" + 4 bytes for hidden vptr + 4 bytes for vbptr) = 20
3) An instance of class CS would need 20 bytes
(4 bytes to hold base class AS + 4 bytes padding + 4 bytes for "int c" + 4 bytes for hidden vptr + 4 bytes for vbptr) = 20
4) An instance of class DS would need 32 bytes
(4 bytes to hold shared base class AS + 4 bytes for "int d" + 8 bytes to hold base class BS (accounting for member size + vbptr size)+ 8 bytes to hold base class CS (accounting for member size + vbptr size) + 4 bytes for hidden DS::vptr + 4 bytes for DS::vbptr) = 32
[Pls note, while implementing vptr-vtable mechanism, the compiler augments vtable with virtual function addresses, there exists a single v-table and a single v-ptr inside the memory model of class DS. Whereas, vbptr would be duplicated inside every virtual base class and inside classes inheriting from them].
Again, all these are compiler specific implementation and may vary across compilers.
Also, define all base class destructors as virtual to get rid of crash.
Upvotes: 0
Reputation: 206508
Whenever you call delete
on a base class pointer pointing to a derived class object then it is mandatory that base class should have a virtual
destructor. Failing to do so results in Undefined Behavior.
So, Your class AS
needs to provide a virtual
destructor:
class AS
{
public:
virtual ~AS(){}
};
Your confusion seems to be output of virtual
functions called through constructor & destructors.
The type of this
within constructor and destructor is the type of the class who's constructor/destructor is being called. So any virtual
function calls from constructor and destructor do not show the dynamic dispatch behavior that you normally expect for virtual functions. Instead the function for that particular class gets called.
As for the sizes class objects. You should not assume the sizes to be anything specific. The compilers are free to add padding bytes which may increase the size of even a non polymorphic class. As for polymorphic classes typically most implementations will add a virtual pointer to the class object to implement the dynamic dispatch mechanism thereby increasing the object size. Note that this is completely implementation dependent.
So always just get the size using sizeof
and never rely on it to be anything specific.
Upvotes: 5