1

Here if I leave class B as empty then total how many vtables will be created here ?

#include <bits/stdc++.h>
using namespace std;

class A{
  public:
      virtual void display(){
        cout<<"A Class"<<endl;
      }
};

class B: public A{
  public:

};

int main() 
{
    A *ob = new B();
    ob->display();//A Class
    return 0;
}

I was assuming still 2 vtable will be created one in A and 1 in B but for Class B it will be empty and as per design of c++ if we call display function then if it doesn't find the function in its vtable then it will look for the vtable in parent class and will set the binding of that function with vptr but, I am not sure of that.

Can anybody explain with the exact concept

I tired finding the answer over the internet but, didn't get the desired answer

Fedrick
  • 23
  • 5
  • 5
    The standard does not specify anything. In fact, the standard doesn't say there has to be one at all. – ChrisMM Dec 03 '22 at 20:32
  • I don't think that B's vtable will be empty, I think it will be a copy of A's vtable (at least as far as the `display` entry is concerned) Certainly I would not expect an implementation to go searching through an inheritance hierarchy just to call a virtual function, that would be very inefficient. – john Dec 03 '22 at 20:34
  • Would the number created here cause any problems? – tadman Dec 03 '22 at 20:34
  • But, there must be some concept behind how the function of base class is called if function is not overriden in the derived class – Fedrick Dec 03 '22 at 20:34
  • Fedrick, the point is that it's really implementation specific. How a compiler chooses to implement such things can vary from compiler to compiler, from version to version. – ChrisMM Dec 03 '22 at 20:37
  • @john so, you mean there will be a vtable in class B as it is the child class of A so, that mean there will be a vtable in every class that will be derived from A or B in above case. If there is another class C inheriting class B then I believe there will be vtable in C also becoz class B I am i right ? – Fedrick Dec 03 '22 at 20:38
  • @Fedrick Yes. If a class has a virtual function, or if it derives from a class with a virtual function then every object of that class will have a pointer to a class specific vtable. Things get more complicated with multiple inheritance, but with single inheritance only, then every such object will have exactly one vtable pointer. – john Dec 03 '22 at 20:46
  • 2
    See [Why should I not #include ?](https://stackoverflow.com/q/31816095) and [Why using namespace std is bad practice](https://stackoverflow.com/questions/1452721). – prapin Dec 03 '22 at 20:54
  • @prapin Thank You for the suggestion will take care for the same – Fedrick Dec 03 '22 at 20:59
  • @john _every object of that class will have a pointer to a class specific vtable_ I was about to say that objects of type `B` could just point to `class A`'s vtable (since, in the OPs example, it can use it as-is), but I think RTTI might mandate that `class B` has a vtable of its own. – Paul Sanders Dec 03 '22 at 22:45
  • 1
    @PaulSanders As well as virtual functions vtables have to support `dynamic_cast`, not sure if that an issue in this particular case, my understanding is getting a little hazy at this point. – john Dec 04 '22 at 06:12
  • @john Yes, you're right, so `B` does indeed need its own vtable. – Paul Sanders Dec 04 '22 at 06:54

1 Answers1

1

Practically B needs some run time type information, which is typically stored as part of the "vtable" , that is distinct from A.

This is because:

bool test(A* a) {
  return dynamic_cast<B*>(a);
}

has to behave differently if we pass a pointer-to-B or a pointer-to-A.

A "typical" way to implement vtables in C++ looks like this:

using vfunc = void(*)(void*);
template<auto creator>
static auto const* get_vtable() {
  static const auto table = creator();
  return &table;
}
struct A_vtable {
  void const* rtti;
  void(*display)(void*);
};
A_vtable create_A_vtable_A() {
  return {
    "This is class A!",
    [](void* self) {
      std::cout<<"A Class"<<std::endl;
    }
  };
}
struct A {
  A_vtable const* vtable;
  A():vtable(get_vtable<&create_A_vtable_A>()) {}
};
struct B_vtable:A_vtable {
};
B_vtable create_B_vtable_B() {
  B_vtable vtable = create_A_vtable_A;
  vtable.rtti = "This is class B!";
}
struct B:A {
  B() {
    vtable = get_vtable<&create_B_vtable_B>();
  }
};

with the note that my runtime type information is intentionally a joke.

That RTTI information in a real situation will tell you how what the runtime type is, and how to get a pointer to the most-derived type. Here I just store a void pointer to a string.

But you'll notice I moved the vtable pointer to a different table in the constructor of B. This is basically how compilers do it (the standard gives compilers lots of freedom, so you cannot assume it looks anything at all like the above, it might not even have a vtable).

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • Okay got it there will be a vtable in class B also but, how the pointer of base class gets binded with the function of base class if there is no function in B that is over riden. And since object is of type class B so, vptr will be pointing to vtable of class B and class B vtable doesn't have any address to virtual function. – Fedrick Dec 04 '22 at 11:21
  • Just wanted to know this interesting concept in depth. – Fedrick Dec 04 '22 at 11:21
  • @Fedrick I have no idea what you are saying. Sorry. – Yakk - Adam Nevraumont Dec 05 '22 at 02:02