Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concept of virtual

I am very new to CPP, learning about late binding polymorphism.

As per what I have read and understood, virtual keyword is used for late binding. which internally at compilation time create a vtable pointed by vptr. So, for example

class BASE{
public:
virtual void f1(){cout<<"BASE F1\n";}
virtual void f2(){cout<<"BASE F2\n";}
void f3(){cout <<"BASE F3\n";}
};

class D1:public BASE{
public: 
    virtual void f1(){cout<<"D1 F1\n";}
    void f2(){cout<<"D1 F2\n";}  
};

class DD1:public D1{
public:
    void f1(){cout<<"DD1 F1\n";}
    void f2(){cout <<"DD1 F2\n";}
};

Here, BASE will be having 2 function in base class vtable:

BASE::f1() 
BASE::f1()

D1 which inherits from BASE, will have inherited vtable:

D1::f1()
BASE::f1

DD1 which inherits from D1, will not have any vtable of its own.

when we create an object:

//case 1:
BASE *b = new D1(); 
b->f1();//will print "D1 F1"
b->BASE::f1();//will print "BASE F1"
b->f2();//will print "D1 F2"
//case 2:
BASE *b1 = new DD1();
b1->f1();//will print "DD1 F1"
b1->D1::f1();//will print "D1 F1"
b1->BASE::f1();//will print"BASE F1"

But, at case: b1->D1::f1(); its giving an compilation error

 error: ‘D1’ is not a base of ‘BASE’

Question: why? should not it print D1 F1 as its virtual function.

After going throw fdump, I found one more interesting thing, which is little confusing;

Vtable for BASE
BASE::_ZTV4BASE: 4u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI4BASE)
16    (int (*)(...))BASE::f1
24    (int (*)(...))BASE::f2

Class BASE
   size=8 align=8
   base size=8 base align=8
BASE (0x7fbc3d2ff120) 0 nearly-empty
    vptr=((& BASE::_ZTV4BASE) + 16u)

Vtable for D1
D1::_ZTV2D1: 4u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI2D1)
16    (int (*)(...))D1::f1
24    (int (*)(...))D1::f2

Class D1
   size=8 align=8
   base size=8 base align=8
D1 (0x7fbc3d31f2d8) 0 nearly-empty
    vptr=((& D1::_ZTV2D1) + 16u)
  BASE (0x7fbc3d2ff180) 0 nearly-empty
      primary-for D1 (0x7fbc3d31f2d8)

Vtable for DD1
DD1::_ZTV3DD1: 4u entries
0     (int (*)(...))0
8     (int (*)(...))(& _ZTI3DD1)
16    (int (*)(...))DD1::f1
24    (int (*)(...))DD1::f2

Class DD1
   size=8 align=8
   base size=8 base align=8
DD1 (0x7fbc3d31f3a8) 0 nearly-empty
    vptr=((& DD1::_ZTV3DD1) + 16u)
  D1 (0x7fbc3d31f410) 0 nearly-empty
      primary-for DD1 (0x7fbc3d31f3a8)
    BASE (0x7fbc3d2ff1e0) 0 nearly-empty
        primary-for D1 (0x7fbc3d31f410)

Question: will not Virtual table of Class BASE get inherited by Class D1, Class D1 vTable & Class BASE get inherited by DD1.? How will inheritance of virtual table take place?

like image 869
Ashutosh Avatar asked Jan 13 '23 05:01

Ashutosh


2 Answers

DD1 which inherits from D1, will not have any vtable of its own.

No, wrong. It will have its own vtable since it overrides virtual functions (the virtual keyword is implied here, since once a function is declared virtual in a base class, it’s virtual everywhere).

Question: why? should not it print D1 F1 as its virtual function.

The static type of b1 is Base*, even if its dynamic type is DD1*. Thus you cannot call b1->D1::f1 because that syntax instructs the compiler to statically resolve the call to a function that (again, statically) is not available in b1. If you absolutely want to execute this call, and know that b1’s dynamic type is in fact D1 (or derived from it), you can cast it to change the static type of the object:

static_cast<D1*>(b1)->D1::f1();
like image 145
Konrad Rudolph Avatar answered Jan 22 '23 06:01

Konrad Rudolph


I will suggest you to pick up some good book(I suggest Thinking in C++, freely available) and go through the chapter on Virtual Functions to get clarity on this confusing topic.

That said, there are few things you have got wrong.

Quote: D1 which inherits from BASE, will have inherited vtable:

D1::f1()

BASE::f1

Actually what happens is that the vtable contents are replaced in case of derived class if it chooses to override the base class virtual functions. In your case you have done that in D1. So the vtable of D1 will have the D1 functions (yes both of them, f1() and f2() ).

So VTable of D1 is:

D1::f1()
D1::f2()

Base class functions disappear/get overwritten in the D1 vTable.

DD1 vtable has the functions of DD1 in them, instead of the D1.

Regarding the error you see, the answer to that is already posted.

like image 34
NotAgain says Reinstate Monica Avatar answered Jan 22 '23 06:01

NotAgain says Reinstate Monica