Reputation: 359
As virtual table is created in compile time, then why do we call this as run time polymorphism in c++?
Upvotes: 7
Views: 7063
Reputation: 351
While it is true that the v-table is created at compile time, when the following code is compiled, the compiler does not know which function will be invoked:
struct A {
virtual void f() { cout << "A::f" << endl;}
};
struct B : public A {
void f() { cout << "B::f" << endl;}
};
int main() {
A* b = new B();
b->f(); // prints "B::f", chosen at runtime
}
So, although the object does not change between compile time and run time, the method B::f is chosen only at run time, because the compiler does not know the dynamic type of the object (which determines which method to invoke).
Upvotes: 0
Reputation: 45665
For this you have to briefly understand what runtime polymorphism is and how it works.
If you have a class hierarchy like this:
class Animal
{
...
virtual void sayHello() {
cout << "hello" << endl;
}
};
class Dog : public Animal
{
...
/*virtual*/ void sayHello() {
cout << "woof!" << endl;
}
};
and call a method on a Dog
instance, you want to be able to call a (virtual) overwritten method of Dog
, not of Animal
. I guess you know why we want this, so I don't want to explain this further.
But how can we know at runtime that an Animal*
is actually a Dog*
? The thing is, we don't have to know what it is, we only have to know which functions to call, or better said, which function pointer to call. All function pointers of virtual functions are stored in a virtual table for each class. You can imagine this as a "guideline" on which code to call for which virtual function, depending on the actual class.
This virtual table is created during compile time (the compiler writes the "guidelines" into the executable file) and each instance points to one of the available virtual tables. So if you say Dog *dog = new Dog
it points to the Dog's virtual table. A call like dog->sayHello()
compiles to a virtual call to the virtual function sayHello
in a class not yet specified...
Then, during runtime a call like dog->sayHello()
will first look for the concrete virtual table stored in the object (the code doesn't know that it is a Dog, only that it is an Animal) and finds a function pointer for the method Dog::sayHello()
.
To answer your question, this mechanism is called runtime polymorphism because we can call methods which overload the this pointer (which means they overload the type of object you call them on) while the decision is made during runtime. You can call the counterpart compiletime polymorphism where the compiler can know the concrete type of object, like in Dog dog; dog.sayHello()
.
Upvotes: 0
Reputation: 14730
The virtual table is an element of the runtime representation of a class type in C++ and a few other OO languages. It is used for dynamic dispatch of virtual method calls. In other words, it's an implementation detail of the dynamic polymorphism feature of C++.
The time when this table is constructed is irrelevant to the dispatch schemes, which defines whether polymorphism is static or dynamic.
Upvotes: 1
Reputation: 254431
As you say, the virtual function table (and other polymorphic information) for each class is generated at compile time.
Each object contains a pointer to the correct table for its dynamic type. This pointer is initialised at run-time when the object is created, and used at run-time to select the correct virtual function to call. That is why it's called run-time polymorphism.
Upvotes: 2
Reputation: 279245
In a typical implementation each class has a virtual table, which is known at compile time.
At runtime, a pointer of type BaseClass *
might point to an object whose type is BaseClass
, or to the base class sub-object of an object whose type is DerivedClass
, where BaseClass
is a base of DerivedClass
. The same applies to references.
In the former case, a virtual call gets looked up in the vtable of BaseClass
. In the latter case, a virtual call gets looked up in the vtable of DerivedClass
. Since the call site doesn't "know" which function gets called until the call is actually executed at runtime, this is called dynamic or runtime polymorphism.
Again in a typical implementation, the way that it finds out which vtable to use is that an object of a type with one or more virtual functions contains a "hidden" additional field that points to the vtable of its complete type. That's for simple inheritance. Multiple and virtual inheritance add complications but the principle is the same, the object provides a pointer to whichever vtable should be used.
Compare this to non-virtual calls, where the complier doesn't need to use any vtable or to know the type of the complete object. It chooses the function according to the type of the pointer or reference.
Upvotes: 9
Reputation: 76245
The virtual table is irrelevant. Runtime polymorphism in C++ means:
struct B {
virtual void f() { std::cout << "In B\n"; }
};
struct D1 : B {
virtual void f() { std::cout << "In D1\n"; }
};
struct D2 : b {
virtual void f() { std::cout << "In D2\n"; }
};
B *bp = new B;
bp->f(); // calls B::f
B *bp1 = new D1;
bp1->f(); // calls D1::f
B *bp2 = new D2;
bp2->f(); // calls D2::f
Even though all three pointers have type B*
, the behavior of the call to f()
depends on the runtime type of the object that the pointer points to.
Upvotes: 3
Reputation: 26164
Virtual tables are created during compilation but used at runtime.
Upvotes: 1