How is pointer to member function implemented in C++? - c++

The pointer to member function in c++ is in three parts:
Offset
Address/index
virtual?
Offset is used for Pointer adjustment when derived object is called using base pointer.
How is this offset implemented? Is it pointer to some table, one table for each derived class and the table contains entries of the form (base X, offset)?
Also, where can I get more info about this?

First you should note that a C++ method can be implemented (and is normally implemented) just as a regular function that accepts an extra hidden parameter before all other parameters, named this.
In other words in
struct P2d {
double x, y;
void doIt(int a, double b) {
...
}
};
the machine code for doIt is the same that would be generated by a C compiler for
void P2d$vid$doIt(P2d *this, int a, double b) {
...
}
and a call like p->doIt(10, 3.14) is compiled to P2d$vid$doIt(p, 10, 3.14);
Given this a method pointer for a simple class that has no virtual methods can be implemented as a regular pointer to the method code (NOTE: I'm using vid for "Void of Int+Double" as a toy example of the "name mangling" that C++ compilers do to handle overloads - different functions with the same name but different parameters).
If the class has virtual methods however this is no more true.
Most C++ compilers implement virtual dispatching unsing a VMT... i.e. in
struct P2d {
...
virtual void doIt(int a, double b);
};
the code for a call like p->doIt(10, 3.14) where p is a P2d * is the same that a C compiler would generate for
(p->$VMTab.vid$doIt)(p, 10, 3.14);
i.e. the instance contains a hidden pointer to a virtual method table that for each member contains the effective code address (assuming the compiler cannot infer that the class of p is indeed P2d and not a derived, as in that case the call can be the same as for a non-virtual method).
Method pointers are required to respect virtual methods... i.e. calling doIt indirectly using a method pointer on an instance derived from P2d is required to call the derived version while the same method pointer is instead to call the base version when used on P2d instances. This means the selection of which code to call depends on both the pointer and the class instance.
A possible implementation is using a trampoline:
void MethodPointerCallerForP2dDoit(P2d *p, int a, double b) {
p->doIt(a, b);
}
and in this case a method pointer is still just pointer to code (but to the trampoline, not to the final method).
An alternative would be to store as method pointer the index of the method inside the VMT instead. This would be feasible because in C++ the method pointer is tied to a specific class and therefore the compiler knows if for that class there are virtual methods or not.
Multiple inheritance do not complicate things for method pointers because everything can be just resolved to a single final VMT table at compile time.

This is a comment regarding 6502's answer, but I lack reputation.
a method pointer for a simple class that has no virtual methods can be implemented as a regular pointer to the method
I believe this statement is incorrect because multiple inheritance complicates things. Consider this code:
struct A {
int a;
void f() {
// use a
}
};
struct B {
int b;
void g() {
// use b
}
};
// C objects may look like this in memory:
//
// |-----|
// | A |
// |-----|
// | B |
// |-----|
//
// Since only one of A and B can be at the start of C in terms of memory
// layout, at least one of the following can't work:
//
// * naively interpreting a pointer to C as a pointer to A
// * naively interpreting a pointer to C as a pointer to B
struct C : A, B {};
void call_ptm(void (C::*ptm)()) {
C c;
// `ptm` could be `A::f` or `B::g`. We don't know. At what offset
// relative to `this` do we expect to find data members then? It depends
// on whether `ptm` points to `A::f` or `B::g`, which isn't known at
// compile time.
(c.*ptm)();
}
One way or another, a pointer to a member function needs to store an offset that can be applied to this upon invocation.

Related

How do upcasting and vtables work together to ensure correct dynamic binding?

So, vtable is a table maintained by the compiler which contains function pointers that point to the virtual functions in that class.
and
Assigning a derived class's object to an ancestor class's object is called up-casting.
Up-casting is handling a derived class instance/object using a base class pointer or reference; the objects are not "assigned to", which implies an overwriting of value ala operator= invocation.
(Thanks to: Tony D)
Now, how it is known at run time "which" class's virtual function is supposed to be called?
Which entry in vtable refers to the function of "particular" derived classes which is supposed to be called at run time?
You can imagine (although the C++ specification doesn't say this) that the vtable is an identifier (or some other metadata that can be used to "find more information" about the class itself) and a list of functions.
So, if we have a class like this:
class Base
{
public:
virtual void func1();
virtual void func2(int x);
virtual std::string func3();
virtual ~Base();
... some other stuff we don't care about ...
};
The compiler will then produce a VTable something like this:
struct VTable_Base
{
int identifier;
void (*func1)(Base* this);
void (*func2)(Base* this, int x);
std::string (*func3)(Base* this);
~Base(Base *this);
};
The compiler will then create an internal structure that, something like this (this is not possible to compile as C++, it's just to show what the compiler actually does - and I call it Sbase to differntiate the actual class Base)
struct SBase
{
VTable_Base* vtable;
inline void func1(Base* this) { vtable->func1(this); }
inline void func2(Base* this, int x) { vtable->func2(this, x); }
inline std::string func3(Base* this) { return vtable->func3(this); }
inline ~Base(Base* this) { vtable->~Base(this); }
};
It also builds the real vtable:
VTable_Base vtable_base =
{
1234567, &Base::func1, &Base::func2, &Base::func3, &Base::~Base
};
And in the constructor for Base, it will set the vtable = vtable_base;.
When we then add a derived class, where we override one function (and by default, the destructor, even if we don't declare one) :
class Derived : public Base
{
virtual void func2(int x) override;
};
The compiler will now make this structure:
struct VTable_Derived
{
int identifier;
void (*func1)(Base* this);
void (*func2)(Base* this, int x);
std::string (*func3)(Base* this);
~Base(Derived *this);
};
and then does the same "structure" building:
struct SDerived
{
VTable_Derived* vtable;
inline void func1(Base* this) { vtable->func1(this); }
inline void func2(Base* this, int x) { vtable->func2(this, x); }
inline std::string func3(Base* this) { return vtable->func3(this); }
inline ~Derived(Derived* this) { vtable->~Derived(this); }
};
We need this structure for when we are using Derived directly rather than through the Base class.
(We rely on the compiler chainin the ~Derived to call ~Base too, just like normal destructors that inherit)
And finally, we build an actual vtable:
VTable_Derived vtable_derived =
{
7654339, &Base::func1, &Derived::func2, &Base::func3, &Derived::~Derived
};
And again,the Derived constructor will set Dervied::vtable = vtable_derived for all instances.
Edit to answer question in comments: The compiler has to carefully place the various components in both VTable_Derived and SDerived such that it matches VTable_Base and SBase, so that when we have a pointer to Base, the Base::vtable and Base::funcN() are matching Derived::vtable and Derived::FuncN. If that doesn't match up, then the inheritance won't work.
If new virtual functions are added to Derived, they must then be placed after the ones inherited from Base.
End Edit.
So, when we do:
Base* p = new Derived;
p->func2();
the code will look up SBase::Func2, which will use the correct Derived::func2 (because the actual vtable inside p->vtable is VTable_Derived (as set by the Derived constructor that is called in conjunction with the new Derived).
I'll take a different route from the other answers and try to fill just the specific gaps in your knowledge, without going very much into the details. I'll address the mechanics just enough to help your understanding.
So, vtable is a table maintained by the compiler which contains function pointers that point to the virtual functions in that class.
The more precise way to say this is as follows:
Every class with virtual methods, including every class that inherits from a class with virtual methods, has its own virtual table. The virtual table of a class points to the virtual methods specific to that class, i.e. either inherited methods, overridden methods or newly added methods. Every instance of such a class contains a pointer to the virtual table that matches the class.
Up-casting is handling a derived class instance/object using a base class pointer or reference; (...)
Perhaps more enlightening:
Up-casting means that a pointer or reference to an instance of class Derived is treated as if it were a pointer or reference to an instance of class Base. The instance itself, however, is still purely an instance of Derived.
(When a pointer is "treated as a pointer to Base", that means that the compiler generates code for dealing with a pointer to Base. In other words, the compiler and the generated code know no better than that they are dealing with a pointer to Base. Hence, a pointer that is "treated as" will have to point to an object that offers at least the same interface as instances of Base. This happens to be the case for Derived because of inheritance. We'll see how this works out below.)
At this point we can answer the first version of your question.
Now, how it is known at run time "which" class's virtual function is supposed to be called?
Suppose we have a pointer to an instance of Derived. First we upcast it, so it is treated as a pointer to an instance of Base. Then we call a virtual method upon our upcasted pointer. Since the compiler knows that the method is virtual, it knows to look for the virtual table pointer in the instance. While we are treating the pointer as if it points to an instance of Base, the actual object has not changed value and the virtual table pointer within it is still pointing to the virtual table of Derived. So at runtime, the address of the method is taken from the virtual table of Derived.
Now, the particular method may be inherited from Base or it might be overridden in Derived. It does not matter; if inherited, the method pointer in the virtual table of Derived simply contains the same address as the corresponding method pointer in the virtual table of Base. In other words, both tables are pointing to the same method implementation for that particular method. If overridden, the method pointer in the virtual table of Derived differs from the corresponding method pointer in the virtual table of Base, so method lookups on instances of Derived will find the overridden method while lookups on instances of Base will find the original version of the method — regardless of whether a pointer to the instance is treated as a pointer to Base or a pointer to Derived.
Finally, it should now be straightforward to explain why the second version of your question is a bit misguided:
Which entry in vtable refers to the function of "particular" derived classes which is supposed to be called at run time?
This question presupposes that vtable lookups are first by method and then by class. It is the other way round: first, the vtable pointer in the instance is used to find the vtable for the right class. Then, the vtable for that class is used to find the right method.
Which entry in vtable refers to the function of "particular" derived
classes which is supposed to be called at run time?
None, it is not an entry in the vtable, but the vtable pointer that is part of each and every object instance that determines which are the correct set of virtual functions for that particular object. This way, depending on the actual vtable pointed to, invoking the "first virtual method" from the vtable may result in the calling of different functions for objects of different types in the same polymorphic hierarchy.
Implementations may vary, but what I personally consider the most logical and performing thing to do is to have the vtable pointer being the first element in the class layout. This way you can dereference the very address of the object to determine its type based on the value of the pointer sitting in that address, since all objects of a given type will have that pointer pointing to the same vtable, which is created uniquely for every object that has virtual methods, which is required to enable features as overriding certain virtual methods.
How do upcasting and vtables work together to ensure correct dynamic
binding?
Upcasting itself isn't strictly needed, neither is downcasting. Remember that you already have the object allocated in memory, and it will already have its vtable pointer set to the correct vtable for that type which is what ensures it, up an down casting doesn't change the vtable for that object, it only changes the pointer you operate through.
Downcasting is needed when you want to access functionality that is not available in the base class and is declared in the derived class. But before you try to do that, you must be sure that particular object is of or inherits the type which declares that functionality, which is where dynamic_cast comes in, when you dynamic cast the compiler generates a check for that vtable entry and whether it inherits the requested type from another table, generated at compile time, and if so the dynamic cast succeeds, otherwise it fails.
The pointer you access the object through doesn't refer to the right set of virtual functions to call, it merely serves as a gauge to which functions in the vtable you can refer to as the developer. That is why it is safe to upcast using a C style or static cast, which performs no runtime checks, because then you only limit your gauge to the functions available in the base class, which are already available in the derived class, so there is no room for error and harm. And that's why you must always use a dynamic cast or some other custom technique still based on virtual dispatch when you downcast, because you have to be sure that object's associated vtable does indeed contain the extra functionality you may invoke.
Otherwise you will get undefined behavior, and of the "bad kind" at that, meaning something fatal will most likely happen, since interpreting arbitrary data as an address of a function of particular signature to be called is a very big no-no.
Also note that in a static context, i.e. when it is known at compile time what the type is, the compiler will most likely not use the vtable to call virtual functions but use direct static calls or even inline certain functions, which will make them that much faster. In such cases upcasting and using a base class pointer instead of the actual object will only diminish that optimization.
Polymorphism and Dynamic Dispatch (hyper-abridged version)
Note: I was not able to fit enough information about multiple inheritance with virtual bases, as there is not much of anything simple about it, and the details would clutter the exposition (further). This answer demonstrates the mechanisms used to implement dynamic dispatch assuming only single inheritance.
Interpreting abstract types and their behaviors visible across module boundaries requires a common Application Binary Interface (ABI). The C++ standard, of course, does not require the implementation of any particular ABI.
An ABI would describe:
The layout of virtual method dispatch tables (vtables)
The metadata required for runtime type checks and cast operations
Name decoration (a.k.a. mangling), calling conventions, and many other things.
Both modules in the following example, external.so and main.o, are assumed to have been linked to the same runtime. Static and dynamic binding give preference to symbols located within the calling module.
An external library
external.h (distributed to users):
class Base
{
__vfptr_t __vfptr; // For exposition
public:
__attribute__((dllimport)) virtual int Helpful();
__attribute__((dllimport)) virtual ~Base();
};
class Derived : public Base
{
public:
__attribute__((dllimport)) virtual int Helpful() override;
~Derived()
{
// Visible destructor logic here.
// Note: This is in the header!
// __vft#Base gets treated like any other imported symbol:
// The address is resolved at load time.
//
this->__vfptr = &__vft#Base;
static_cast<Base *>(this)->~Base();
}
};
__attribute__((dllimport)) Derived *ReticulateSplines();
external.cpp:
#include "external.h" // the version in which the attributes are dllexport
__attribute__((dllexport)) int Base::Helpful()
{
return 47;
}
__attribute__((dllexport)) Base::~Base()
{
}
__attribute__((dllexport)) int Derived::Helpful()
{
return 4449;
}
__attribute__((dllexport)) Derived *ReticulateSplines()
{
return new Derived(); // __vfptr = &__vft#Derived in external.so
}
external.so (not a real binary layout):
__vft#Base:
[offset to __type_info#Base] <-- in external.so
[offset to Base::~Base] <------- in external.so
[offset to Base::Helpful] <----- in external.so
__vft#Derived:
[offset to __type_info#Derived] <-- in external.so
[offset to Derived::~Derived] <---- in external.so
[offset to Derived::Helpful] <----- in external.so
Etc...
__type_info#Base:
[null base offset field]
[offset to mangled name]
__type_info#Derived:
[offset to __type_info#Base]
[offset to mangled name]
Etc...
An application using the external library
special.hpp:
#include <iostream>
#include "external.h"
class Special : public Base
{
public:
int Helpful() override
{
return 55;
}
virtual void NotHelpful()
{
throw std::exception{"derp"};
}
};
class MoreDerived : public Derived
{
public:
int Helpful() override
{
return 21;
}
~MoreDerived()
{
// Visible destructor logic here
this->__vfptr = &__vft#Derived; // <- the version in main.o
static_cast<Derived *>(this)->~Derived();
}
};
class Related : public Base
{
public:
virtual void AlsoHelpful() = 0;
};
class RelatedImpl : public Related
{
public:
void AlsoHelpful() override
{
using namespace std;
cout << "The time for action... Is now!" << endl;
}
};
main.cpp:
#include "special.hpp"
int main(int argc, char **argv)
{
Base *ptr = new Base(); // ptr->__vfptr = &__vft#Base (in external.so)
auto r = ptr->Helpful(); // calls "Base::Helpful" in external.so
// r = 47
delete ptr; // calls "Base::~Base" in external.so
ptr = new Derived(); // ptr->__vfptr = &__vft#Derived (in main.o)
r = ptr->Helpful(); // calls "Derived::Helpful" in external.so
// r = 4449
delete ptr; // calls "Derived::~Derived" in main.o
ptr = ReticulateSplines(); // ptr->__vfptr = &__vft#Derived (in external.so)
r = ptr->Helpful(); // calls "Derived::Helpful" in external.so
// r = 4449
delete ptr; // calls "Derived::~Derived" in external.so
ptr = new Special(); // ptr->__vfptr = &__vft#Special (in main.o)
r = ptr->Helpful(); // calls "Special::Helpful" in main.o
// r = 55
delete ptr; // calls "Base::~Base" in external.so
ptr = new MoreDerived(); // ptr->__vfptr = & __vft#MoreDerived (in main.o)
r = ptr->Helpful(); // calls "MoreDerived::Helpful" in main.o
// r = 21
delete ptr; // calls "MoreDerived::~MoreDerived" in main.o
return 0;
}
main.o:
__vft#Derived:
[offset to __type_info#Derivd] <-- in main.o
[offset to Derived::~Derived] <--- in main.o
[offset to Derived::Helpful] <---- stub that jumps to import table
__vft#Special:
[offset to __type_info#Special] <-- in main.o
[offset to Base::~Base] <---------- stub that jumps to import table
[offset to Special::Helpful] <----- in main.o
[offset to Special::NotHelpful] <-- in main.o
__vft#MoreDerived:
[offset to __type_info#MoreDerived] <---- in main.o
[offset to MoreDerived::~MoreDerived] <-- in main.o
[offset to MoreDerived::Helpful] <------- in main.o
__vft#Related:
[offset to __type_info#Related] <------ in main.o
[offset to Base::~Base] <-------------- stub that jumps to import table
[offset to Base::Helpful] <------------ stub that jumps to import table
[offset to Related::AlsoHelpful] <----- stub that throws PV exception
__vft#RelatedImpl:
[offset to __type_info#RelatedImpl] <--- in main.o
[offset to Base::~Base] <--------------- stub that jumps to import table
[offset to Base::Helpful] <------------- stub that jumps to import table
[offset to RelatedImpl::AlsoHelpful] <-- in main.o
Etc...
__type_info#Base:
[null base offset field]
[offset to mangled name]
__type_info#Derived:
[offset to __type_info#Base]
[offset to mangled name]
__type_info#Special:
[offset to __type_info#Base]
[offset to mangled name]
__type_info#MoreDerived:
[offset to __type_info#Derived]
[offset to mangled name]
__type_info#Related:
[offset to __type_info#Base]
[offset to mangled name]
__type_info#RelatedImpl:
[offset to __type_info#Related]
[offset to mangled name]
Etc...
Invocation is (or might not be) Magic!
Depending on the method and what can be proven at the binding side, a virtual method call may be bound statically or dynamically.
A dynamic virtual method call will read the target function's address from the vtable pointed to by a __vfptr member.
The ABI describes how functions are ordered in vtables. For example: They might be ordered by class, then lexicographically by mangled name (which includes information about const-ness, parameters, etc...). For single inheritance, this approach guarantees that a function's virtual dispatch index will always be the same, regardless of how many distinct implementations there are.
In the examples given here, destructors are placed at the beginning of each vtable, if applicable. If the destructor is trivial and non-virtual (not defined or does nothing), the compiler may elide it entirely, and not allocate a vtable entry for it.
Base *ptr = new Special{};
MoreDerived *md_ptr = new MoreDerived{};
// The cast below is checked statically, which would
// be a problem if "ptr" weren't pointing to a Special.
//
Special *sptr = static_cast<Special *>(ptr);
// In this case, it is possible to
// prove that "ptr" could point only to
// a Special, binding statically.
//
ptr->Helpful();
// Due to the cast above, a compiler might not
// care to prove that the pointed-to type
// cannot be anything but a Special.
//
// The call below might proceed as follows:
//
// reg = sptr->__vptr[__index_of#Base::Helpful] = &Special::Helpful in main.o
//
// push sptr
// call reg
// pop
//
// This will indirectly call Special::Helpful.
//
sptr->Helpful();
// No cast required: LSP is satisfied.
ptr = md_ptr;
// Once again:
//
// reg = ptr->__vfptr[__index_of#Base::Helpful] = &MoreDerived::Helpful in main.o
//
// push ptr
// call reg
// pop
//
// This will indirectly call MoreDerived::Helpful
//
ptr->Helpful();
The logic above is the same for any invocation site that requires dynamic binding. In the example above, it doesn't matter exactly what type ptr or sptr point to; the code will just load a pointer at a known offset, then blindly call it.
Type casting: Ups and Downs
All information about a type hierarchy must be available to the compiler when translating a cast or function call expression. Symbolically, casting is just a matter of traversing a directed graph.
Up-casting in this simple ABI can be performed entirely at compile time. The compiler needs only to examine the type hierarchy to determine if the source and target types are related (there is a path from the source to the target in the type graph). By the substitution principle, a pointer to a MoreDerived also points to a Base and can be interpreted as such. The __vfptr member is at the same offset for all types in this hierarchy, so RTTI logic doesn't need to handle any special cases (in certain implementations of VMI, it would need to grab another offset from a type thunk to grab another vptr and so on...).
Down-casting, however, is different. Since casting from a base type to a derived type involves determining if the pointed-to object has a compatible binary layout, it is necessary to perform an explicit type check (conceptually, this is "proving" that the extra information exists beyond the end of the structure assumed at compile time).
Note that there are multiple vtable instances for the Derived type: One in external.so and one in main.o. This is because a virtual method defined for Derived (its destructor) appears in every translation unit that includes external.h.
Even though the logic is identical in both cases, both images in this example need to have their own copy. This is why type checking cannot be performed using addresses alone.
A down-cast is then performed by walking a type graph (copied in both images) starting from the source type decoded at runtime, comparing mangled names until the compile-time target is matched.
For example:
Base *ptr = new MoreDerived();
// ptr->__vfptr = &__vft::MoreDerived in main.o
//
// This provides the code below with a starting point
// for dynamic cast graph traversals.
// All searches start with the type graph in the current image,
// then all other linked images, and so on...
// This example is not exhaustive!
// Starts by grabbing &__type_info#MoreDerived
// using the offset within __vft#MoreDerived resolved
// at load time.
//
// This is similar to a virtual method call: Just grab
// a pointer from a known offset within the table.
//
// Search path:
// __type_info#MoreDerived (match!)
//
auto *md_ptr = dynamic_cast<MoreDerived *>(ptr);
// Search path:
// __type_info#MoreDerived ->
// __type_info#Derived (match!)
//
auto *d_ptr = dynamic_cast<Derived *>(ptr);
// Search path:
// __type_info#MoreDerived ->
// __type_info#Derived ->
// __type_info#Base (no match)
//
// Did not find a path connecting RelatedImpl to MoreDerived.
//
// rptr will be nullptr
//
auto *rptr = dynamic_cast<RelatedImpl *>(ptr);
At no point in the code above did ptr->__vfptr need to change. The static nature of type deduction in C++ requires the implementation to satisfy the substitution principle at compile time, meaning that the actual type of an object cannot change at runtime.
Summary
I've understood this question as one about the mechanisms behind dynamic dispatch.
To me, "Which entry in vtable refers to the function of "particular" derived classes which is supposed to be called at run time?", is asking how a vtable works.
This answer is intended to demonstrate that type casting affects only the view of an object's data, and that the implementation of dynamic dispatch in these examples operate independently of it. However, type casting does affect dynamic dispatch in the case of multiple inheritance, where determining which vtable to use may require multiple steps (an instance of a type with multiple bases may have multiple vptrs).
casting
casting is a concept associated with variable. So any variable can be casted. It can be casted up or down.
char charVariable = 'A';
int intVariable = charVariable; // upcasting
int intVariable = 20;
char charVariale = intVariable; // downcasting
for system defined data type Up cast or downcast is based on your current variable and it mainly related to how much memory compiler is allocating to both compared variable.
If you are assigning a variable which is allocating less memory than the type what is converting to, is called up cast.
If you are assigning a variable which is allocating more memory than the type what is converting to, is called down cast.
Down cast create some problem when the value is trying to cast can't fit in to that allocated memory area.
Upcasting in Class level
Just like system defined data type we can have object of base class and derived class. So if we want to convert derived type to base type , it is known as down upcasting. That can be achieved by pointer of a base class pointing to a derived class type.
class Base{
public:
void display(){
cout<<"Inside Base::display()"<<endl;
}
};
class Derived:public Base{
public:
void display(){
cout<<"Inside Derived::display()"<<endl;
}
};
int main(){
Base *baseTypePointer = new Derived(); // Upcasting
baseTypePointer.display(); // because we have upcasted we want the out put as Derived::display() as output
}
output
Inside Base::display()
Excepted
Inside Derived::display()
In the above scenario the output wasn't as excepted. Its because we don't have the v-table and vptr (virtual pointer) in the object the base pointer will call the Base::display() though we have assigned derived type to the base pointer.
To avoid this problem c++ gives us virtual concept. Now the base class display function need to be changed to a virtual type.
virtual void display()
full code is:
class Base{
public:
virtual void display(){
cout<<"Inside Base::display()"<<endl;
}
};
class Derived:public Base{
public:
void display(){
cout<<"Inside Derived::display()"<<endl;
}
};
int main(){
Base *baseTypePointer = new Derived(); // Upcasting
baseTypePointer.display(); // because we have upcasted we want the out put as Derived::display() as output
}
output
Inside Derived::display()
Excepted
Inside Derived::display()
To understand this we need to understand v-table and vptr;
when ever compiler find a virtual along with a function it will generate a virtual table for each of the classes (both Base and all the derived classes).
If virtual function is present than every object will be containing vptr (virtual pointer) pointing to the respective class vtable and vtable will contain the pointer to the respective class virtual function. when you will call the function throught vptr the virutal function will get called and it will invoke the respective class function and we will achieve the required output.
I believe, this is best explained by implementing polymorphism in C. Given these two C++ classes:
class Foo {
virtual void foo(int);
};
class Bar : public Foo {
virtual void foo(int);
virtual void bar(double);
};
the C structure definitions (i. e. the header file) would look like this:
//For class Foo
typedef struct Foo_vtable {
void (*foo)(int);
} Foo_vtable;
typedef struct Foo {
Foo_vtable* vtable;
} Foo;
//For class Bar
typedef struct Bar_vtable {
Foo_vtable super;
void (*bar)(double);
}
typedef struct Bar {
Foo super;
} Bar;
As you see, there are two structure definitions for each class, one for the vtable and one for the class itself. Note also that both structures for class Bar include a base class object as their first member which allows us upcasting: both (Foo*)myBarPointer and (Foo_vtable*)myBar_vtablePointer are valid. As such, given a Foo*, it is safe to find the location of the foo() member by doing
Foo* basePointer = ...;
(basePointer->vtable->foo)(7);
Now, lets take a look at how we can actually fill the vtables. For that we write some constructors that use some statically defined vtable instances, this is what the foo.c file could look like
#include "..."
static void foo(int) {
printf("Foo::foo() called\n");
}
Foo_vtable vtable = {
.foo = &foo,
};
void Foo_construct(Foo* me) {
me->vtable = vtable;
}
This makes sure that it is possible to execute (basePointer->vtable->foo)(7) on every object that has been passed to Foo_construct(). Now, the code for Bar is quite similar:
#include "..."
static void foo(int) {
printf("Bar::foo() called\n");
}
static void bar(double) {
printf("Bar::bar() called\n");
}
Bar_vtable vtable = {
.super = {
.foo = &foo
},
.bar = &bar
};
void Bar_construct(Bar* me) {
Foo_construct(&me->super); //construct the base class.
(me->vtable->foo)(7); //This will print Foo::foo()
me->vtable = vtable;
(me->vtable->foo)(7); //This will print Bar::foo()
}
I have used static declarations for the member functions to avoid having to invent a new name for each implementation, static void foo(int) restricts the visibility of the function to the source file. However, it can still be called from other files by the use of a function pointer.
Usage of these classes could look like this:
#include "..."
int main() {
//First construct two objects.
Foo myFoo;
Foo_construct(&myFoo);
Bar myBar;
Bar_construct(&myBar);
//Now make some pointers.
Foo* pointer1 = &myFoo, pointer2 = (Foo*)&myBar;
Bar* pointer3 = &myBar;
//And the calls:
(pointer1->vtable->foo)(7); //prints Foo::foo()
(pointer2->vtable->foo)(7); //prints Bar::foo()
(pointer3->vtable->foo)(7); //prints Bar::foo()
(pointer3->vtable->bar)(7.0); //prints Bar::bar()
}
Once you know how this works, you know how C++ vtables work. The only difference is that in C++ the compiler does the work that I did myself in the code above.
Let me try to explain it with some examples:-
class Base
{
public:
virtual void function1() {cout<<"Base :: function1()\n";};
virtual void function2() {cout<<"Base :: function2()\n";};
virtual ~Base(){};
};
class D1: public Base
{
public:
~D1(){};
virtual void function1() { cout<<"D1 :: function1()\n";};
};
class D2: public Base
{
public:
~D2(){};
virtual void function2() { cout<< "D2 :: function2\n";};
};
So, compiler would generate three vtables one for each class as these classes have virtual functions. ( Although it's compiler-dependant ).
NOTE:- vtables contain only pointers to virtual functions. Non-virtual functions would still be resolved at compile time...
You are right in saying that vtables are nothing just pointers to functions. vtables for these classes would be like something:-
vtable for Base:-
&Base::function1 ();
&Base::function2 ();
&Base::~Base ();
vtable for D1:-
&D1::function1 ();
&Base::function2 ();
&D1::~D1();
vtable for D2:-
&Base::function1 ();
&D2::function2 ();
&D2::~D2 ();
vptr is a pointer which is used for look-up purpose on this table. Each object of polymorphic class has extra allocated space for vptr in it ( Although where vptr would be in object is entirely implementation dependant ).Generally vptr is at the beginning of object.
With taking all into account , if I make a call to func, compiler at run time would check what b is actually pointing to:-
void func ( Base* b )
{
b->function1 ();
b->function2 ();
}
Let's say we have object of D1 passed to func. Compiler would resolve calls in following manner:-
First it would fetch vptr from object and then it will use it to get correct address of function to call. SO, in this case vptr would give access to D1's vtable. and when it looksup for function1 it would get the address of function1 defined in base class. In case of call to function2, it would get address of base's function2.
Hope I have clarified your doubts to your satisfaction...
The implementation is compiler specific. Here I am going to do some thoughts that have NOTHING TO DO WITH ANY ACTUAL KNOWLEDGE of how exactly it is done in compilers, but just with some minimal requirements that are needed in order to work as required. Keep in mind that each instance of a class with virtual methods knows at run time which is the class it belongs too.
Lets suppose we have a chain of base and derived classes with a length of 10 ( so a derived class has a gran gran ... gran father ).
We may call these classes base0 base1 ... base9 where base9 derives from base8 etc.
Each of these classes define a method as: virtual void doit(){ ... }
Let's suppose that in the base class we use that method inside a method called "dowith_doit" non overridden in any derived class.
The semantics of c++ imply that depending on the base class of the instance we have at hand, we must apply to that instance the "doit" defined in the base class of the instance at hand.
Essentially we have two possible ways of doing it:
a) Assign to any such virtual method a number that must be different for each method defined in the chain of derived classes. In that case the number could be also a hash of the name of the method.
Each class defines a table with 2 columns were the first column holds the number of the method and the second column the address of the function. In that case each class will have a vtable with so many rows as the number of virtual methods defined inside the class.
The execution of the method happens by searching inside the class the method under consideration. That search may be done linearly ( slow ) of by bisections ( when there is an order based on the number of the method).
b) Assign to any such method a progressively increasing integer number (for each different method in the chain of classes), and for each class define a table with only one column. For virtual methods defined inside the class the function address will be in the raw defined by the number of the method. There will be many rows with null pointers because each class doesn't override always the methods of previous classes.
The implementation may choose in order to improve efficiency to fill null rows with the address hold in the ancestor class of the class under consideration.
Essentially no other simple ways exist in order work with virtual methods efficiently.
I suppose that only the second solution (b) is used in actual implementations, because the trade of between space overhead used for non existing methods compared to execution efficiency of case (b) is favorable for case b (taking into consideration too that methods are limited in number - may be 10 20 50 but not 5000 ).
Upon instantiation every class with at least one virtual function gets a hidden member usually called vTable (or virtual dispatch table, VDT).
class Base {
hidden: // not part of the language, just to illustrate.
static VDT baseVDT; // per class VDT for base
VDT *vTable; // per object instance
private:
...
public:
virtual int base1();
virtual int base2();
...
};
The vTable contains pointers to all functions in Base.
As a hidden part of Base's constructor vTable gets assigned to baseVDT.
VDT Base::baseVDT[] = {
Base::base1,
Base::base2
};
class Derived : public Base {
hidden:
static VDT derivedVDT; // per class VDT for derived
private:
...
public:
virtual int base2();
...
};
The vTable for Derived contains pointers to all functions defined in Base followed by functions defined in Derived . When objects of type Derived gets constructed, vTable gets set to derivedVDT.
VDT derived::derivedVDT[] = {
// functions first defined in Base
Base::base1,
Derived::base2, // override
// functions first defined in Derived are appended
Derived::derived3
}; // function 2 has an override in derived.
Now if we have
Base *bd = new Derived;
Derived *dd = new Derived;
Base *bb = new Base;
bd points to an object of type derived who's vTable points to Derived
So the function calls
x = bd->base2();
y = bb->base2();
actually is
// "base2" here is the index into vTable for base2.
x = bd->vTable["base2"](); // vTable points to derivedVDT
y = bb->vTable["base2"](); // vTable points to baseVDT
The index is the same in both due to the construction of the VDT. This also means the compiler knows the index at the moment of compilation.
This could also be implemented as
// call absolute address to virtual dispatch function which calls the right base2.
x = Base::base2Dispatch(bd->vTable["base2"]);
inline Base::base2Dispatch(void *call) {
return call(); // call through function pointer.
}
Which with O2 or O3 will be the same.
There are some special cases:
dd points to a derived or more derived object and base2 is declared final then
z = dd->base2();
actually is
z = Derived::base2(); // absolute call to final method.
If dd pointed to a Base object or anything else your in undefined behaviour land and the compiler can still do this.
The other case is if the compiler sees there are only a few derived classes from Base it could generate a Oracle interface for base2. [free after a MS or Intel compiler guy at some C++ conference in 2012 or 2013? showing that (~500%?) more code gives (2+ times?) speedup on average]
inline Base::base2Dispatch(void *call) {
if (call == Derived::base2) // most likely from compilers static analysis or profiling.
return Derived::base2(); // call absolute address
if (call == Base::base2)
return Base::base2(); // call absolute address
// Backup catch all solution in case of more derived classes
return call(); // call through function pointer.
}
Why on earth do you want to do this as a compiler??? more code is bad, unneeded branches diminish performance!
Because calling a function pointer is very slow on many architectures, optimistic example
Get the address from memory, 3+ cycles.
Delayed pipeline while waiting for ip value, 10 cycles, on some processors 19+ cycles.
If the most complex modern cpu's can predict the actual jump address [BTB] as well as it does branch prediction, this might be a loss. Else the ~8 extra instructions will easily save the 4*(3+10) instructions lost due to pipeline stalls (if the prediction failure rate is less than 10-20%).
If the branches in the two if's both predict taken (ie evaluate to false) the ~2 cycles lost is nicely covered by the memory latency to get the call address and we are no worse off.
If one of the if's are mispredicts the the BTB will most likely also be wrong. Then the cost of the mispredicts is around 8 cycles of which 3 are paid by the memory latency, and the correct not take or the 2nd if might save the day or we pay the full 10+ pipeline stall.
If only the 2 possibilities exists one of them will be taken and we save the pipeline stall from the function pointer call and we will max. get one mispredict resulting in no (significant) worse performance than calling directly.
If the memory delay is longer and the result is correctly predicted the effect is much larger.

Why is a virtual table required only in case of virtual functions?

From http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/, code such as
class Base
{
public:
virtual void function1() {};
virtual void function2() {};
};
class D1: public Base
{
public:
virtual void function1() {};
};
class D2: public Base
{
public:
virtual void function2() {};
};
generates a virtual table similar to http://www.learncpp.com/images/CppTutorial/Section12/VTable.gif:
The virtual table as above makes sense. After all the objects need a way to call functions, and need to use function pointers to find them.
What I do not understand is why this is only required in case of using virtual functions? I am definitely missing something since a virtual table does not directly depend on virtual functions.
As an example, if the code being used were
class Base
{
public:
void function1() {};
void function2() {};
};
...
Base b;
b.function1();
and there is no virtual table (meaning there is no pointer to where the function resides), how would the b.function1() call resolve?
Or is it that we have a table in this case as well, just that it is not called a virtual table? In that case the question would arise as to why we need a new kind of table for virtual functions?
[If] there is no virtual table (meaning there is no pointer to where the function resides), how would the b.function1() call resolve?
There is a "pointer", inside the compiler as it's parsing and analysing your code. The compiler's the thing that decides where the function will be generated, so it knows how calls to said function should resolve. In concert with the linker, this all happens tidily within the build process.
The only reason that this doesn't work for virtual functions is that which function you call depends on a type known only at runtime; in fact the same function pointers are present verbatim in the virtual table, written there by the compiler. It's just that in this case, there are multiple to choose from, and they cannot be chosen from until long (read: potentially months or even years!) after the compiler ceases to be involved at all.
There's already a good answer, but I'll attempt a slightly simpler (albeit longer) one:
Think of a non-virtual method of the form
class A
{
public:
int fn(int arg1);
};
as equivalent to a free function of the form:
int fn(A* me, int arg1); // overload A
where me corresponds to the this pointer inside the method version.
If you now have a subclass:
class B : public A
{
public:
int fn(int arg1);
};
this is equivalent to a free function like this:
int fn(B* me, int arg1); // overload B
Note that the first argument has a different type to the free function we declared earlier - the function is overloaded on the type of the first argument.
If you now have some code calling fn() it will choose the overload based on the static type (compile time type) of the first argument:
A* p;
B* q;
// ...
// assign valid pointer values to p and q
// ...
int a = fn(p, 0); // will call overload A
int b = fn(q, 0); // will call overload B
The compiler can and will determine the function to call at compile time in each case and can emit assembly code with a fixed function address or address offset. The concept of a runtime virtual table is nonsensical here.
Now, when I said to think of the method version as equivalent to the free function version, you'll find that at the assembly language level, they are equivalent. The only difference will be the so-called mangled name that encodes the type in the compiled function name and distinguishes overloaded functions. The fact that you call methods via p->fn(0), that is, with the first argument before the method name is pure syntactic sugar - you're not actually dereferencing the pointer p in the example, even though it looks like it. You're just passing p as the implicit this argument. So, to continue the above example,
p->fn(0); // will always call A::fn()
q->fn(0); // will always call B::fn()
because fn being a non-virtual method means the compiler dispatches on the this pointer's static type, which it can do at compile time.
Although virtual functions use the same calling syntax as non-virtual member functions, you are in fact dereferencing the object pointer; specifically, you're dereferencing the pointer to the object's class's virtual table.

What happens when an upcast pointer is passed by reference to a function expecting derived?

I've inherited something similar to this code:
class Base
{
public:
virtual double getElement(int i) {return NULL;}
virtual Derived* GetAsDerived() {return this;}
};
class Derived : public Base
{
public:
virtual double getElement(int i) {return vec[i];}
private:
std::vector<double>;
};
And a function as follows:
void f(Base& b)
{
Derived* d = b.GetAsDerived();
}
The program flow is something similar to this
Derived A;
/* get data into vector in A */
f(A);
After the call to GetAsDerived() in f .The vector in the object pointed by d contains junk.Inside the debugger I can go back in the call stack and see that the vector inside A still has valid data.
I am sure that that all this weird upcasting - downcasting is the cause but I was not able to find a formal explanation in the specs or online.
So why does it fail in such a manner?
Upcasting is formally defined in 4.10/3 of the standard. Downcasting is in 5.2.9/5, although that's not specifically what you're doing.
Addressing the title of your question, it's not possible to pass (or return) a base class pointer to (from) a function whose parameters (return type) indicate a derived class pointer. If the parameters indicate a reference to base class pointer, then it's not possible to pass a derived class pointer by reference. If a base class pointer value, it is possible to pass a derived pointer because of the implicit conversion.
I can't say why your code fails: as commented above, your real code must fail for different reasons than your example code does, since your example code doesn't work at all.
In function f,Derived* d = b.GetAsDerived();does not change anything about b,so it can't change the object b points to,in this case A.In f,If there is b = d or something alike,then A will be changed.

Multiple Inheritance

#include<iostream>
using namespace std;
class A
{
int a;
int b;
public:
void eat()
{
cout<<"A::eat()"<<endl;
}
};
class B: public A
{
public:
void eat()
{
cout<<"B::eat()"<<endl;
}
};
class C: public A
{
public:
void eat()
{
cout<<"C::eat()"<<endl;
}
};
class D: public B, C
{
};
int foo(A *ptr)
{
ptr->eat();
}
main()
{
D obj;
foo(&(obj.B)); //error. How do i call with D's B part.
}
The above foo call is a compile time error.
I want to call foo with obj's B part without using virtual inheritance. How do i do that.
Also, in case of virtual inheritance, why the offset information need to be stored in the vtable. This can be determined at the compile time itself. In the above case, if we pass foo with D's object, at compile time only we can calculate the offset of D's A part.
Inheriting twice
With double inheritance you have an ambiguity - the compiler cannot know which of the two A bases do you want to use. If you want to have two A bases (sometimes you may want to do this), you may select between them by casting to B or C. The most appropriate from default casts here is the static_cast (as the weakest available), however it is not realy needed (it is still stronger than your case needs), as you are not casting to a derived type. A custom safe_cast template should do the job:
/// cast using implicit conversions only
template <class To,class From>
inline To safe_cast( const From &from ) {return from;}
main()
{
D obj;
foo(safe_cast<B *>(&obj)); //error. How do i call with D's B part.
}
Compile time types - use templates
Also, in case of virtual inheritance,
why the offset information need to be
stored in the vtable. This can be
determined at the compile time itself.
In the above case, if we pass foo with
D's object, at compile time only we
can calculate the offset of D's A
part.
This is a misconception. The foo function as it is written now has no compile type information about ptr type other than it is A *, even if you pass B * or C*. If you want foo to be able to act based on the type passed compile time, you need to use templates:
template <class TypeDerivedFromA>
int foo(TypeDerivedFromA *ptr)
{
ptr->eat();
}
Virtual Inheritance
Your questions mentions virtual inheritance. If you want to use virtual inheritance, you need to specify so:
class B: public virtual A ...
class C: public virtual A ...
With this the code would compile, but with this solution there is no way you could select between B::A or C::A (there is only one A), therefore this is probably not what you are about.
Virtual functions
Furthermore, your questions seems to be confusing two different concepts, virtual inheritance (which means sharing one base class between two intermediate base classes) and virtual functions (which mean allowing derived class function to be called via base class pointer). If you want the B::eat to be called using A pointer, you can do this without virtual inheritance (actually virtual inheritance would prevent you doing so, as explained above), using virtual functions:
class A
{
int a;
int b;
public:
virtual void eat()
{
cout<<"A::eat()"<<endl;
}
};
If virtual functions are not acceptable for you, the compile time mechanism for this are templates, as explained above.
Use a cast - static_cast is required here to cast up the heirarchy.
main()
{
D obj;
foo(static_cast<B*>(&obj));
}
First of all, obj does not have a member named B. It Inherits from B, which means that it inherits all of B's members as its own.
You can call:
foo(static_cast<B*>(&obj)); to make it work.
I don't think the static_cast will work.
When you are on the foo function, all the compiler knows is that you have a pointer to A, whatever the type you passed as parameter.
If you don't use virtual inheritance, then I think there is no way to call a B function from a pointer to A.

How are virtual functions and vtable implemented?

We all know what virtual functions are in C++, but how are they implemented at a deep level?
Can the vtable be modified or even directly accessed at runtime?
Does the vtable exist for all classes, or only those that have at least one virtual function?
Do abstract classes simply have a NULL for the function pointer of at least one entry?
Does having a single virtual function slow down the whole class? Or only the call to the function that is virtual? And does the speed get affected if the virtual function is actually overwritten or not, or does this have no effect so long as it is virtual.
How are virtual functions implemented at a deep level?
From "Virtual Functions in C++":
Whenever a program has a virtual function declared, a v - table is constructed for the class. The v-table consists of addresses to the virtual functions for classes that contain one or more virtual functions. The object of the class containing the virtual function contains a virtual pointer that points to the base address of the virtual table in memory. Whenever there is a virtual function call, the v-table is used to resolve to the function address. An object of the class that contains one or more virtual functions contains a virtual pointer called the vptr at the very beginning of the object in the memory. Hence the size of the object in this case increases by the size of the pointer. This vptr contains the base address of the virtual table in memory. Note that virtual tables are class specific, i.e., there is only one virtual table for a class irrespective of the number of virtual functions it contains. This virtual table in turn contains the base addresses of one or more virtual functions of the class. At the time when a virtual function is called on an object, the vptr of that object provides the base address of the virtual table for that class in memory. This table is used to resolve the function call as it contains the addresses of all the virtual functions of that class. This is how dynamic binding is resolved during a virtual function call.
Can the vtable be modified or even directly accessed at runtime?
Universally, I believe the answer is "no". You could do some memory mangling to find the vtable but you still wouldn't know what the function signature looks like to call it. Anything that you would want to achieve with this ability (that the language supports) should be possible without access to the vtable directly or modifying it at runtime. Also note, the C++ language spec does not specify that vtables are required - however that is how most compilers implement virtual functions.
Does the vtable exist for all objects, or only those that have at least one virtual function?
I believe the answer here is "it depends on the implementation" since the spec doesn't require vtables in the first place. However, in practice, I believe all modern compilers only create a vtable if a class has at least 1 virtual function. There is a space overhead associated with the vtable and a time overhead associated with calling a virtual function vs a non-virtual function.
Do abstract classes simply have a NULL for the function pointer of at least one entry?
The answer is it is unspecified by the language spec so it depends on the implementation. Calling the pure virtual function results in undefined behavior if it is not defined (which it usually isn't) (ISO/IEC 14882:2003 10.4-2). In practice it does allocate a slot in the vtable for the function but does not assign an address to it. This leaves the vtable incomplete which requires the derived classes to implement the function and complete the vtable. Some implementations do simply place a NULL pointer in the vtable entry; other implementations place a pointer to a dummy method that does something similar to an assertion.
Note that an abstract class can define an implementation for a pure virtual function, but that function can only be called with a qualified-id syntax (ie., fully specifying the class in the method name, similar to calling a base class method from a derived class). This is done to provide an easy to use default implementation, while still requiring that a derived class provide an override.
Does having a single virtual function slow down the whole class or only the call to the function that is virtual?
This is getting to the edge of my knowledge, so someone please help me out here if I'm wrong!
I believe that only the functions that are virtual in the class experience the time performance hit related to calling a virtual function vs. a non-virtual function. The space overhead for the class is there either way. Note that if there is a vtable, there is only 1 per class, not one per object.
Does the speed get affected if the virtual function is actually overridden or not, or does this have no effect so long as it is virtual?
I don't believe the execution time of a virtual function that is overridden decreases compared to calling the base virtual function. However, there is an additional space overhead for the class associated with defining another vtable for the derived class vs the base class.
Additional Resources:
http://www.codersource.net/published/view/325/virtual_functions_in.aspx (via way back machine)
http://en.wikipedia.org/wiki/Virtual_table
http://www.codesourcery.com/public/cxx-abi/abi.html#vtable
Can the vtable be modified or even directly accessed at runtime?
Not portably, but if you don't mind dirty tricks, sure!
WARNING: This technique is not recommended for use by children, adults under the age of 969, or small furry creatures from Alpha Centauri. Side effects may include demons which fly out of your nose, the abrupt appearence of Yog-Sothoth as a required approver on all subsequent code reviews, or the retroactive addition of IHuman::PlayPiano() to all existing instances]
In most compilers I've seen, the vtbl * is the first 4 bytes of the object, and the vtbl contents are simply an array of member pointers there (generally in the order they were declared, with the base class's first). There are of course other possible layouts, but that's what I've generally observed.
class A {
public:
virtual int f1() = 0;
};
class B : public A {
public:
virtual int f1() { return 1; }
virtual int f2() { return 2; }
};
class C : public A {
public:
virtual int f1() { return -1; }
virtual int f2() { return -2; }
};
A *x = new B;
A *y = new C;
A *z = new C;
Now to pull some shenanigans...
Changing class at runtime:
std::swap(*(void **)x, *(void **)y);
// Now x is a C, and y is a B! Hope they used the same layout of members!
Replacing a method for all instances (monkeypatching a class)
This one's a little trickier, since the vtbl itself is probably in read-only memory.
int f3(A*) { return 0; }
mprotect(*(void **)x,8,PROT_READ|PROT_WRITE|PROT_EXEC);
// Or VirtualProtect on win32; this part's very OS-specific
(*(int (***)(A *)x)[0] = f3;
// Now C::f1() returns 0 (remember we made x into a C above)
// so x->f1() and z->f1() both return 0
The latter is rather likely to make virus-checkers and the link wake up and take notice, due to the mprotect manipulations. In a process using the NX bit it may well fail.
Does having a single virtual function slow down the whole class?
Or only the call to the function that is virtual? And does the speed get affected if the virtual function is actually overwritten or not, or does this have no effect so long as it is virtual.
Having virtual functions slows down the whole class insofar as one more item of data has to be initialized, copied, … when dealing with an object of such a class. For a class with half a dozen members or so, the difference should be neglible. For a class which just contains a single char member, or no members at all, the difference might be notable.
Apart from that, it is important to note that not every call to a virtual function is a virtual function call. If you have an object of a known type, the compiler can emit code for a normal function invocation, and can even inline said function if it feels like it. It's only when you do polymorphic calls, via a pointer or reference which might point at an object of the base class or at an object of some derived class, that you need the vtable indirection and pay for it in terms of performance.
struct Foo { virtual ~Foo(); virtual int a() { return 1; } };
struct Bar: public Foo { int a() { return 2; } };
void f(Foo& arg) {
Foo x; x.a(); // non-virtual: always calls Foo::a()
Bar y; y.a(); // non-virtual: always calls Bar::a()
arg.a(); // virtual: must dispatch via vtable
Foo z = arg; // copy constructor Foo::Foo(const Foo&) will convert to Foo
z.a(); // non-virtual Foo::a, since z is a Foo, even if arg was not
}
The steps the hardware has to take are essentially the same, no matter whether the function is overwritten or not. The address of the vtable is read from the object, the function pointer retrieved from the appropriate slot, and the function called by pointer. In terms of actual performance, branch predictions might have some impact. So for example, if most of your objects refer to the same implementation of a given virtual function, then there is some chance that the branch predictor will correctly predict which function to call even before the pointer has been retrieved. But it doesn't matter which function is the common one: it could be most objects delegating to the non-overwritten base case, or most objects belonging to the same subclass and therefore delegating to the same overwritten case.
how are they implemented at a deep level?
I like the idea of jheriko to demonstrate this using a mock implementation. But I'd use C to implement something akin to the code above, so that the low level is more easily seen.
parent class Foo
typedef struct Foo_t Foo; // forward declaration
struct slotsFoo { // list all virtual functions of Foo
const void *parentVtable; // (single) inheritance
void (*destructor)(Foo*); // virtual destructor Foo::~Foo
int (*a)(Foo*); // virtual function Foo::a
};
struct Foo_t { // class Foo
const struct slotsFoo* vtable; // each instance points to vtable
};
void destructFoo(Foo* self) { } // Foo::~Foo
int aFoo(Foo* self) { return 1; } // Foo::a()
const struct slotsFoo vtableFoo = { // only one constant table
0, // no parent class
destructFoo,
aFoo
};
void constructFoo(Foo* self) { // Foo::Foo()
self->vtable = &vtableFoo; // object points to class vtable
}
void copyConstructFoo(Foo* self,
Foo* other) { // Foo::Foo(const Foo&)
self->vtable = &vtableFoo; // don't copy from other!
}
derived class Bar
typedef struct Bar_t { // class Bar
Foo base; // inherit all members of Foo
} Bar;
void destructBar(Bar* self) { } // Bar::~Bar
int aBar(Bar* self) { return 2; } // Bar::a()
const struct slotsFoo vtableBar = { // one more constant table
&vtableFoo, // can dynamic_cast to Foo
(void(*)(Foo*)) destructBar, // must cast type to avoid errors
(int(*)(Foo*)) aBar
};
void constructBar(Bar* self) { // Bar::Bar()
self->base.vtable = &vtableBar; // point to Bar vtable
}
function f performing virtual function call
void f(Foo* arg) { // same functionality as above
Foo x; constructFoo(&x); aFoo(&x);
Bar y; constructBar(&y); aBar(&y);
arg->vtable->a(arg); // virtual function call
Foo z; copyConstructFoo(&z, arg);
aFoo(&z);
destructFoo(&z);
destructBar(&y);
destructFoo(&x);
}
So you can see, a vtable is just a static block in memory, mostly containing function pointers. Every object of a polymorphic class will point to the vtable corresponding to its dynamic type. This also makes the connection between RTTI and virtual functions clearer: you can check what type a class is simply by looking at what vtable it points at. The above is simplified in many ways, like e.g. multiple inheritance, but the general concept is sound.
If arg is of type Foo* and you take arg->vtable, but is actually an object of type Bar, then you still get the correct address of the vtable. That's because the vtable is always the first element at the address of the object, no matter whether it's called vtable or base.vtable in a correctly-typed expression.
Usually with a VTable, an array of pointers to functions.
Here is a runnable manual implementation of virtual table in modern C++. It has well-defined semantics, no hacks and no void*.
Note: .* and ->* are different operators than * and ->. Member function pointers work differently.
#include <iostream>
#include <vector>
#include <memory>
struct vtable; // forward declare, we need just name
class animal
{
public:
const std::string& get_name() const { return name; }
// these will be abstract
bool has_tail() const;
bool has_wings() const;
void sound() const;
protected: // we do not want animals to be created directly
animal(const vtable* vtable_ptr, std::string name)
: vtable_ptr(vtable_ptr), name(std::move(name)) { }
private:
friend vtable; // just in case for non-public methods
const vtable* const vtable_ptr;
std::string name;
};
class cat : public animal
{
public:
cat(std::string name);
// functions to bind dynamically
bool has_tail() const { return true; }
bool has_wings() const { return false; }
void sound() const
{
std::cout << get_name() << " does meow\n";
}
};
class dog : public animal
{
public:
dog(std::string name);
// functions to bind dynamically
bool has_tail() const { return true; }
bool has_wings() const { return false; }
void sound() const
{
std::cout << get_name() << " does whoof\n";
}
};
class parrot : public animal
{
public:
parrot(std::string name);
// functions to bind dynamically
bool has_tail() const { return false; }
bool has_wings() const { return true; }
void sound() const
{
std::cout << get_name() << " does crrra\n";
}
};
// now the magic - pointers to member functions!
struct vtable
{
bool (animal::* const has_tail)() const;
bool (animal::* const has_wings)() const;
void (animal::* const sound)() const;
// constructor
vtable (
bool (animal::* const has_tail)() const,
bool (animal::* const has_wings)() const,
void (animal::* const sound)() const
) : has_tail(has_tail), has_wings(has_wings), sound(sound) { }
};
// global vtable objects
const vtable vtable_cat(
static_cast<bool (animal::*)() const>(&cat::has_tail),
static_cast<bool (animal::*)() const>(&cat::has_wings),
static_cast<void (animal::*)() const>(&cat::sound));
const vtable vtable_dog(
static_cast<bool (animal::*)() const>(&dog::has_tail),
static_cast<bool (animal::*)() const>(&dog::has_wings),
static_cast<void (animal::*)() const>(&dog::sound));
const vtable vtable_parrot(
static_cast<bool (animal::*)() const>(&parrot::has_tail),
static_cast<bool (animal::*)() const>(&parrot::has_wings),
static_cast<void (animal::*)() const>(&parrot::sound));
// set vtable pointers in constructors
cat::cat(std::string name) : animal(&vtable_cat, std::move(name)) { }
dog::dog(std::string name) : animal(&vtable_dog, std::move(name)) { }
parrot::parrot(std::string name) : animal(&vtable_parrot, std::move(name)) { }
// implement dynamic dispatch
bool animal::has_tail() const
{
return (this->*(vtable_ptr->has_tail))();
}
bool animal::has_wings() const
{
return (this->*(vtable_ptr->has_wings))();
}
void animal::sound() const
{
(this->*(vtable_ptr->sound))();
}
int main()
{
std::vector<std::unique_ptr<animal>> animals;
animals.push_back(std::make_unique<cat>("grumpy"));
animals.push_back(std::make_unique<cat>("nyan"));
animals.push_back(std::make_unique<dog>("doge"));
animals.push_back(std::make_unique<parrot>("party"));
for (const auto& a : animals)
a->sound();
// note: destructors are not dispatched virtually
}
This answer has been incorporated into the Community Wiki answer
Do abstract classes simply have a NULL for the function pointer of at least one entry?
The answer for that is that it is unspecified - calling the pure virtual function results in undefined behavior if it is not defined (which it usually isn't) (ISO/IEC 14882:2003 10.4-2). Some implementations do simply place a NULL pointer in the vtable entry; other implementations place a pointer to a dummy method that does something similar to an assertion.
Note that an abstract class can define an implementation for a pure virtual function, but that function can only be called with a qualified-id syntax (ie., fully specifying the class in the method name, similar to calling a base class method from a derived class). This is done to provide an easy to use default implementation, while still requiring that a derived class provide an override.
You can recreate the functionality of virtual functions in C++ using function pointers as members of a class and static functions as the implementations, or using pointer to member functions and member functions for the implementations. There are only notational advantages between the two methods... in fact virtual function calls are just a notational convenience themselves. In fact inheritance is just a notational convenience... it can all be implemented without using the language features for inheritance. :)
The below is crap untested, probably buggy code, but hopefully demonstrates the idea.
e.g.
class Foo
{
protected:
void(*)(Foo*) MyFunc;
public:
Foo() { MyFunc = 0; }
void ReplciatedVirtualFunctionCall()
{
MyFunc(*this);
}
...
};
class Bar : public Foo
{
private:
static void impl1(Foo* f)
{
...
}
public:
Bar() { MyFunc = impl1; }
...
};
class Baz : public Foo
{
private:
static void impl2(Foo* f)
{
...
}
public:
Baz() { MyFunc = impl2; }
...
};
I'll try to make it simple :)
We all know what virtual functions are in C++, but how are they implemented at a deep level?
This is an array with pointers to functions, which are implementations of a particular virtual function. An index in this array represents particular index of a virtual function defined for a class. This includes pure virtual functions.
When a polymorphic class derives from another polymorphic class, we may have the following situations:
The deriving class does not add new virtual functions nor overrides any. In this case this class shares the vtable with the base class.
The deriving class adds and overrides virtual methods. In this case it gets its own vtable, where the added virtual functions have index starting past the last derived one.
Multiple polymorphic classes in the inheritance. In this case we have an index-shift between second and next bases and the index of it in the derived class
Can the vtable be modified or even directly accessed at runtime?
Not standard way - there's no API to access them. Compilers may have some extensions or private APIs to access them, but that may be only an extension.
Does the vtable exist for all classes, or only those that have at least one virtual function?
Only those that have at least one virtual function (be it even destructor) or derive at least one class that has its vtable ("is polymorphic").
Do abstract classes simply have a NULL for the function pointer of at least one entry?
That's a possible implementation, but rather not practiced. Instead there is usually a function that prints something like "pure virtual function called" and does abort(). The call to that may occur if you try to call the abstract method in the constructor or destructor.
Does having a single virtual function slow down the whole class? Or only the call to the function that is virtual? And does the speed get affected if the virtual function is actually overwritten or not, or does this have no effect so long as it is virtual.
The slowdown is only dependent on whether the call is resolved as direct call or as a virtual call. And nothing else matters. :)
If you call a virtual function through a pointer or reference to an object, then it will be always implemented as virtual call - because the compiler can never know what kind of object will be assigned to this pointer in runtime, and whether it is of a class in which this method is overridden or not. Only in two cases the compiler can resolve the call to a virtual function as a direct call:
If you call the method through a value (a variable or result of a function that returns a value) - in this case the compiler has no doubts what the actual class of the object is, and can "hard-resolve" it at compile time.
If the virtual method is declared final in the class to which you have a pointer or reference through which you call it (only in C++11). In this case compiler knows that this method cannot undergo any further overriding and it can only be the method from this class.
Note though that virtual calls have only overhead of dereferencing two pointers. Using RTTI (although only available for polymorphic classes) is slower than calling virtual methods, should you find a case to implement the same thing two such ways. For example, defining virtual bool HasHoof() { return false; } and then override only as bool Horse::HasHoof() { return true; } would provide you with ability to call if (anim->HasHoof()) that will be faster than trying if(dynamic_cast<Horse*>(anim)). This is because dynamic_cast has to walk through the class hierarchy in some cases even recursively to see if there can be built the path from the actual pointer type and the desired class type. While the virtual call is always the same - dereferencing two pointers.
Each object has a vtable pointer that points to an array of member functions.
Something not mentioned here in all these answers is that in case of multiple inheritance, where the base classes all have virtual methods. The inheriting class has multiple pointers to a vmt.
The result is that the size of each instance of such an object is bigger.
Everybody knows that a class with virtual methods has 4 bytes extra for the vmt, but in case of multiple inheritance it is for each base class that has virtual methods times 4. 4 being the size of the pointer.
Burly's answers are correct here except for the question:
Do abstract classes simply have a NULL for the function pointer of at least one entry?
The answer is that no virtual table is created at all for abstract classes. There is no need since no objects of these classes can be created!
In other words if we have:
class B { ~B() = 0; }; // Abstract Base class
class D : public B { ~D() {} }; // Concrete Derived class
D* pD = new D();
B* pB = pD;
The vtbl pointer accessed through pB will be the vtbl of class D. This is exactly how polymorphism is implemented. That is, how D methods are accessed through pB. There is no need for a vtbl for class B.
In response to Mike's comment below...
If the B class in my description has a virtual method foo() that is not overridden by D and a virtual method bar() that is overridden, then D's vtbl will have a pointer to B's foo() and to its own bar(). There is still no vtbl created for B.
very cute proof of concept i made a bit earlier(to see if order of inheritence matters); let me know if your implementation of C++ actually rejects it(my version of gcc only gives a warning for assigning anonymous structs, but that's a bug), i'm curious.
CCPolite.h:
#ifndef CCPOLITE_H
#define CCPOLITE_H
/* the vtable or interface */
typedef struct {
void (*Greet)(void *);
void (*Thank)(void *);
} ICCPolite;
/**
* the actual "object" literal as C++ sees it; public variables be here too
* all CPolite objects use(are instances of) this struct's structure.
*/
typedef struct {
ICCPolite *vtbl;
} CPolite;
#endif /* CCPOLITE_H */
CCPolite_constructor.h:
/**
* unconventionally include me after defining OBJECT_NAME to automate
* static(allocation-less) construction.
*
* note: I assume CPOLITE_H is included; since if I use anonymous structs
* for each object, they become incompatible and cause compile time errors
* when trying to do stuff like assign, or pass functions.
* this is similar to how you can't pass void * to windows functions that
* take handles; these handles use anonymous structs to make
* HWND/HANDLE/HINSTANCE/void*/etc not automatically convertible, and
* require a cast.
*/
#ifndef OBJECT_NAME
#error CCPolite> constructor requires object name.
#endif
CPolite OBJECT_NAME = {
&CCPolite_Vtbl
};
/* ensure no global scope pollution */
#undef OBJECT_NAME
main.c:
#include <stdio.h>
#include "CCPolite.h"
// | A Greeter is capable of greeting; nothing else.
struct IGreeter
{
virtual void Greet() = 0;
};
// | A Thanker is capable of thanking; nothing else.
struct IThanker
{
virtual void Thank() = 0;
};
// | A Polite is something that implements both IGreeter and IThanker
// | Note that order of implementation DOES MATTER.
struct IPolite1 : public IGreeter, public IThanker{};
struct IPolite2 : public IThanker, public IGreeter{};
// | implementation if IPolite1; implements IGreeter BEFORE IThanker
struct CPolite1 : public IPolite1
{
void Greet()
{
puts("hello!");
}
void Thank()
{
puts("thank you!");
}
};
// | implementation if IPolite1; implements IThanker BEFORE IGreeter
struct CPolite2 : public IPolite2
{
void Greet()
{
puts("hi!");
}
void Thank()
{
puts("ty!");
}
};
// | imposter Polite's Greet implementation.
static void CCPolite_Greet(void *)
{
puts("HI I AM C!!!!");
}
// | imposter Polite's Thank implementation.
static void CCPolite_Thank(void *)
{
puts("THANK YOU, I AM C!!");
}
// | vtable of the imposter Polite.
ICCPolite CCPolite_Vtbl = {
CCPolite_Thank,
CCPolite_Greet
};
CPolite CCPoliteObj = {
&CCPolite_Vtbl
};
int main(int argc, char **argv)
{
puts("\npart 1");
CPolite1 o1;
o1.Greet();
o1.Thank();
puts("\npart 2");
CPolite2 o2;
o2.Greet();
o2.Thank();
puts("\npart 3");
CPolite1 *not1 = (CPolite1 *)&o2;
CPolite2 *not2 = (CPolite2 *)&o1;
not1->Greet();
not1->Thank();
not2->Greet();
not2->Thank();
puts("\npart 4");
CPolite1 *fake = (CPolite1 *)&CCPoliteObj;
fake->Thank();
fake->Greet();
puts("\npart 5");
CPolite2 *fake2 = (CPolite2 *)fake;
fake2->Thank();
fake2->Greet();
puts("\npart 6");
#define OBJECT_NAME fake3
#include "CCPolite_constructor.h"
fake = (CPolite1 *)&fake3;
fake->Thank();
fake->Greet();
puts("\npart 7");
#define OBJECT_NAME fake4
#include "CCPolite_constructor.h"
fake2 = (CPolite2 *)&fake4;
fake2->Thank();
fake2->Greet();
return 0;
}
output:
part 1
hello!
thank you!
part 2
hi!
ty!
part 3
ty!
hi!
thank you!
hello!
part 4
HI I AM C!!!!
THANK YOU, I AM C!!
part 5
THANK YOU, I AM C!!
HI I AM C!!!!
part 6
HI I AM C!!!!
THANK YOU, I AM C!!
part 7
THANK YOU, I AM C!!
HI I AM C!!!!
note since I am never allocating my fake object, there is no need to do any destruction; destructors are automatically put at the end of scope of dynamically allocated objects to reclaim the memory of the object literal itself and the vtable pointer.