I am having problems to understand why abstract classes have vtables. I know that this question has come up under the following posts, which I read so bear with me a moment:
VTABLE for abstract classes C++
Does an abstract classes have a VTABLE?
Why does an abstract class have a vtable?
Here is what I know:
vtables are used to enable polymorphic behavior when I use a derived object via a pointer of the base class. If I now call a virtual method of that base class it will go to the vtable of base look at the real type of the object it is pointing to and look for the closest specialized override of that method and use that one. An class is abstract if it contains at least one pure virtual function, meaning it cannot be instanciated. If it cannot be instanciated I cannot create a base pointer so I can't use it in a polymorphic way? So why would it be able to have a vtable?
If it cannot be instanciated I cannot create a base pointer
This is where your reasoning goes off the rails. Not being able to instantiate does not imply that you cannot create a base pointer. A minimal example:
struct B {
virtual void foo() = 0;
};
struct D : B {
void foo() override {};
};
int main(){
D d;
B* ptr = &d; // base pointer to abstract class
}
So why would it be able to have a vtable?
So that virtual function calls can be dispatched to the implementations in concrete subclasses. On second thought, this is what the vptr is for in general.
The vtable of the abstract base can be used to implement dynamic_cast. It can also be used, in cases where pure virtual functions are called from the constructor or the destructor of the base, as in those cases the vptr won't yet point to the derived vtable.
Related
Is there a good reason why a virtual function is virtual by default in a derived class and it is not even possible to remove virtuality completely in the derived function?
The reason why I want this behaviour is the same reason I do not want every function to be virtual by default. The compiler might generate vtables which costs performance.
There should be a vtable for the base class (I want polymorphism there), but no vtable for the derived class (I do not want polymorphism there, why should I want that, only because it derives of a class with polymorphism?).
The problem I want to solve is to better understand virtual functions. I just do not get this design decision and wonder if there is any reason for this.
A vtable for a particular class has pointers to the virtual functions for that particular class. A vtable for a base class does not point to the virtual functions overridden by a derived class. There could be many derived classes, and the base class knows about precisely zero of them, so there's no way to have pointers to those functions. Only a derived class's vtable may have pointers to the derived class's functions.
The point of a virtual function is that, if you convert an object of the derived class to a base class pointer/reference, then calling any virtual function declared in the base class must call the most derived class's version of that function for that object. The only way to do that is if the vtable for that object has a pointer to the most-derived-class's version of that function. And that can only happen if the vtable for that object is the derived class's vtable.
That's how vtable's work.
If the derived class doesn't have a vtable of its own, which points to its own overridden member functions rather than the base class functions, then virtual dispatch can't work.
I do not want polymorphism there, why should I want that, only because it derives of a class with polymorphism?
But you do want polymorphism. You asked for it. If you inherit from a polymorphic base class and override one of its virtual functions, you are declaring the intent to use polymorphism. If you didn't want polymorphism, you wouldn't inherit from a polymorphic base class.
I think you are confused about what a vtable does. A vtable for a class C deriving from B basically maps functions specifiers to function pointers for class C. So if you do
B* ptr = new C;
ptr->foo();
we have to look up at runtime, which function to call. In the end, we need a function pointer to C::foo since B cannot possibly know where that lies, since it does not know about C at all. Hence, here we need C's vtable to make the call. Now you could argue that we do not need Bs vtable here. But ptr could also to an Object of type B, so there you need the B vtable.
Arguably, one could do something like this (of course, pseudo code):
virtual_call_to_foo(B* ptr) {
if(ptr->is_actually_base_class) {
ptr->B::foo(); // non-virtual call
} else {
ptr->vtable["foo"](); // indirect call
}
}
But that wouldn't be better than just also using a vtable for B since you already have the indirection there.
Further, note that a call through a pointer to C won't be virtual if C::foo is final:
B* ptr = new C;
ptr->foo(); // virtual call
static_cast<C*>(ptr)->foo(); // non-virtual call, the compiler can inline this
When a method is declared, the declaring class decides if it is virtual, according to the nature of what the method does.
When you override such a method, your overriding method is a specialized version of doing the exact same thing. Your overriding method cannot decide that it is doing something that cannot be specialized, the base class has already made that decision. The nature of the method is decided by the class that originally declared it, the base class.
Vtables are an implementation detail that should not affect any of this.
So I'm studying for an C++ exam and I've come across the following question:
If you were to inherit from std::vector would you create a virtual
destructor?
Since std::vector does not have a virtual destructor would there be any point in me creating one?
I think std::vector is a red herring. First let me rewrite the question as
If you were to write a class A that inherits from std::vector, would you give it a virtual destructor?
Then the only relevant thing here is whether std::vector does already have a virtual destructor. If it had, the destructor of A would always be virtual automatically, no matter whether you specify it with the virtual keyword or not. But std::vector does not have a virtual destructor. So the reference to it can be dropped:
If you were to write a class A, would you give it a virtual destructor?
The answer would still be that it will be automatically virtual if A inherits from any other class with virtual destructor, so the only interesting case left is:
If you were to write a class A, which does not inherit from any class with virtual destructor, would you give it a virtual destructor?
Now this is a very general question and as mentioned in the comments, it depends on whether you intend to use the class as polymorphic base, i.e. whether you want to allow deletion of objects of a type derived from A through a pointer/reference to A.
A class needs a virtual destructor if your design calls for deleting an object of a type derived from that class through a pointer to that class. That is,
class base {
};
class derived : public base {
};
void f() {
base *bp = new derived;
delete bp; // undefined behavior: base does not have a virtual destructor
}
std::vector, by design does not have a virtual destructor. It is not intended to be used as a base class.
So if your (flawed) design calls for deriving from std::vector<whatever> and deriving from your derived type and deleting objects of your ultimate type through pointers to your base type, then your base type must have a virtual destructor. But that has nothing to do with std::vector or with the fact that your base type is derived from std::vector. It's needed because of the way your base class is used.
In C++, there is no class representation at run-time but I can always call an overridden virtual method in the derived class. where is that overridden method saved in the vtable? here's a piece of code to demonstrate:
struct B1 {
virtual void f() { ... }
};
struct B2 {
virtual void f() { ... }
virtual void g() { ... }
};
struct D : B1, B2 {
void f() { ... }
virtual void h() { ... }
};
What's the memory layout for an object of class D ? Where are B1::f and B2::f saved in that memory layout (if they're saved at all) ?
An object d of Class D will have only a pointer to the VMT of class D, which will contain a pointer to D::f.
Since B1:f and B2::f can be called only statically from the scope of D class, there is no need for object d to keep a dynamic pointer to those overridden methods.
This of cause is not defined in the standard, this is just the usual/logical implementation of the compiler.
In fact the picture is more complicated, since the VMT of class D incorporates the VMTs of classes B1 and B2. But anyway, there is no need to dynamically call B1::f until an object of class B1 is created.
When compiler uses vtable method of virtual dispatch*, the address of the overriden member function is stored in the vtable of the base class in which the function is defined.
Each class has access to vtables of all of its base classes. These vtables are stored outside of the memory layout for the class itself. Each class with virtual member functions, declared or inherited, has a single pointer to its own vtable. When you call an overriden member function, you supply the name of the base class whose member function you wish to call. The compiler knows about vtables of all classes, to it knows how to locate the vtable of your base class, does the lookup at compile time, and calls the member function directly.
Here is a short example:
struct A {
virtual void foo() { cout << "A"; }
};
struct B : public A { }; // No overrides
struct C : public B {
virtual void foo() { cout << "C"; }
void bar() { B::foo(); }
};
Demo.
In the example above the compiler needs to look up B::foo, which is not defined in class B. The compiler consults its symbol table to find out that B::foo is implemented in A, and generates the call to A::foo inside C::bar.
* vtables is not the only method of implementing virtual dispatch. C++ standard does not require vtables to be used.
Although nothing is mandated in the C++ standard, every known C++ implementation uses the same approach: every class with at least a virtual function has a vptr (pointer to vtable).
You didn't mention virtual inheritance which is a different, more subtle inheritance relation; non-virtual inheritance is a simple exclusive relation between a base class subobject and a derived class. I will assume all inheritance relations are not virtual in this answer.
Here I assume we derive from classes with at least a virtual function.
In case of single inheritance, the vptr from the base class is reused. (Not reusing it just wastes space and run time.) The base class is called "primary base class".
In case of multiple inheritance, the layout of the derived class contains the layout of every base class, just like the layout of a struct in C contains the layout of every member. The layout of D is B1 then B2 (in any order actually, but the source code order is usually kept).
The first class is the primary base class: in D the vptr from B1 points to a complete vtable for D, the vtable with all the virtual functions of D. Each vptr from a non-primary base class points to a secondary vtable of D: a vtable with only the virtual functions from this secondary base class.
The constructor of D must initialize every vptr of the class instance to point to the appropriate vtable of D.
class base
{
public:
virtual void showbase() {
// ----------
}
};
class base1 {
public:
virtual void showbase1() {
// -------
}
};
class derived : public base, public base1
{
void showbase() {
// ----
}
void showbase1() {
// -------
}
};
int main()
{
base* p = new derived();
p->showbase1();
base1* p1 = new derived();
p1->showbase();
}
As per my understanding about virtual function is that compiler deals it with run time (vtable mechanism), then why I am getting compile time error.
To simulate a compiler, consider what a compiler sees:
class base
{
public:
virtual void showbase() {
// ----------
}
};
base* p = /*blah blah*/;
p->showbase1();
Yes, base is a polymorphic class. And p is indeed a pointer-tobase. But since p points just to a base, and importantly not to a base1 (where showbase1 lives) the compiler interprets the above code like this. Obviously, I'm paraphrasing:
Here is a class named `base` with a single virtual method called `showbase`.
Here is a pointer to a `base` object. Call the method named `showbase1`
And the compiler complains:
Um, excuse me buddy, but base doesn't have a method called
showbase1.
You asked:
[My] understanding about virtual function is that compiler deals with
it at run time. Why I am getting compile time error?
Because the code you've written is nonsense. Here basically is how polymorphism works.
You define a base class with virtual methods.
You define a derived class that overrides those virtual methods.
The compiler creates a vtable which maps the names of the methods in the base class to the implementation in the derived class.
When you call a method in the base class through a pointer (or ref) to the base class, the derived class' implementation is called.
But what you are trying to do is:
Define a base class with virtual methods.
Define a derived class which overrides those virtual methods.
Call a function in a completely different class.
As per my understanding about virtual function is that compiler deals it with run time (vtable mechanism), then why I am getting compile time error.
"Deals with it" is pretty vague and vtables are not magic; In C++ virtual dispatch allows for the actual function called to be one that overrides the statically declared virtual function. That means that the function which is being overridden must be known at compile time.
The vtable does not contain information that would be necessary to look up functions at run-time. Instead, it's basically just a list of pointers to overriding functions. The base provides a complete list of its virtual functions and so, given a particular base type, the compiler knows at compile-time where to go in the vtable for that base for a particular function override; The compiler can generate code that goes directly to that spot in the vtable, gets the pointer, and calls the overriding function.
Then, at run-time, when the actual object of derived type is created, the derived object's constructor fills in the base's vtable, so that anything checking the vtable will get pointers to the derived type's functions.
So the problem with your code is that the function you're calling, showbase(), is not on the list of virtual functions for the type the compiler knows you're accessing, base1; The compiler can't know where in base1's vtable to get a pointer for a function override named showbase(), because there is no such entry in base1's vtable.
A base class pointer to a derived class can only access the member functions defined in the base class. It is illegal to try and access other functions defined in the derived class through it. In your case base class does not define showbase1 and therefore this is illegal
base* p = new derived();
p->showbase1(); //illegal
However, you can do this:
p->showbase(); // legal because showbase is a member function of base
Similarly you can't access showbase1 using a base class pointer
base1* p1 = new derived();
p1->showbase(); //illegal
p1->showbase1(); //legal
Your base class(es) only know about their own member functions, so you can't use it this way. You could do this instead:
base* p = new derived();
p->showbase();
base1* p1 = new derived();
p1->showbase1();
To answer your question about runtime polymorphism, it is dealing with runtime polymorphism (late binding) via the vtable, as you say. But with multiple inheritance, there is essentially a vtable for for each base class. You can't access one base class' vtable via a pointer to the other base class.
p'static type s type is base and hence you can only call with it functions that have been definied into base even if at the end, it will be the functions from derived which will be called because p's dynamic type is derived
Same thing happens for p1.
Maybe you meant p->showbase(); and p1->showbase1();
I read a lot of people writing "a virtual table exists for a class that has a virtual function declared in it".
My question is, does a vtable exists only for a class that has a virtual function or does it also exist for classes derived from that class.
e.g
class Base{
public:
virtual void print(){cout<<"Base Print\n";}
};
class Derived:public Base{
public:
void print(){cout<<"Derived print\n";}
};
//From main.cpp
Base* b = new Derived;
b->print();
Question: Had there been no vtable for class derived then the output would not have been "derived print". So IMO there exists a vtable for any class that has virtual function declared and also in classes inheriting from that class. Is this correct ?
As far as only virtual-function-specific functionality is considered, in a traditional approach to vtable implementation derived class would need a separate version of vtable if and only if that derived class overrides at least one virtual function. In your example, Derived overrides virtual function print. Since Derived has its own version of print, the corresponding entry in Derived vtable is different from that in Base vtable. This would normally necessitate a separate vtable for Derived.
If Derived didn't override anything at all, formally it still would be a separate polymorphic class, but in order to make its virtual functions work properly we could have simply reused Base vtable for Derived as well. So, technically there wouldn't be any need for a separate vtable for Derived.
However, in practical implementations, the data structure that we usually refer to as "vtable", often holds some additional class-specific information as well. That extra information is so class-specific that most of the time it becomes impossible to share vtables between different classes in hierarchy, even if they use the same set of virtual functions. For example, in some implementations the vtable pointer stored in each polymorphic object points to data structure that also stores so called "RTTI information" about the class. For this reason, in most (if not all) practical implementations each polymorphic class gets its own vtable, even if the virtual function pointers stored in those tables happen to be the same.
Yes, your understanding is correct. Any class that has a base with any virtual functions has a vtable.
Yes it's true. Actually, given base's defintion:
class derived:public base{
public:
void print(){cout<<"derived print\n";}
};
is completely equivalent to:
class derived:public base{
public:
virtual void print(){cout<<"derived print\n";}
};
... because you already defined print as virtual in base.
I'd wish the compiler would enforce that...
Yes, that's true. A class inherits all data members from its base class, including the vtable. However, vtable entries are adjusted accordingly (for example if the class overrides a base class virtual method, the corresponding entry in the vtable must point to its own implementation).
But keep in mind that the concept of a 'vtable' is common practice used by vitually every compiler, but it is not compulsory nor standardized.