If a virtual table is created at compile time, then why do we call it run-time polymorphism?

How is a virtual table created at compile time, then why do we call it run-time polymorphism in C ++?

+6
source share
8 answers

Because the search is done at runtime.

+12
source

In a typical implementation, each class has a virtual table that is known at compile time.

At startup, a pointer of type BaseClass * can point to an object whose type is BaseClass , or to a sub-object of the base class of an object whose type is DerivedClass , where BaseClass is the base of DerivedClass . The same goes for links.

In the first case, the virtual call is viewed in the vtable BaseClass table. In the latter case, the virtual call is viewed in the vtable DerivedClass table. Since the call site does not β€œknow” which function is called until the call is executed at run time, this is called dynamic or temporary polymorphism.

Again, in a typical implementation, the way it detects which vtable to use is that a type object with one or more virtual functions contains a "hidden" extra field that points to a vtable of its full type. This is for easy inheritance. Multiple and virtual inheritance add complexity, but the principle is the same, the object provides a pointer to which vtable should be used.

Compare this to non-virtual calls, where the compiler should not use any vtable or know the type of the complete object. It selects a function according to the type of pointer or reference.

+8
source

A virtual table does not matter. Run-time 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 

Although all three pointers are of type B* , the behavior of the f() call depends on the type of runtime of the object that the pointer points to.

+3
source

Virtual tables are created at compile time, but are used at runtime.

+1
source

As you say, a table of virtual functions (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 initialized at run time when the object is created, and used at run time to select the correct virtual function to call. This is why it is called run-time polymorphism.

+1
source

To do this, you need to briefly understand what polymorphism is at runtime and how it works.

If you have a class hierarchy:

 class Animal { ... virtual void sayHello() { cout << "hello" << endl; } }; class Dog : public Animal { ... /*virtual*/ void sayHello() { cout << "woof!" << endl; } }; 

and call the method in the Dog instance, you want to be able to (() rewrite the Dog method, not Animal . You probably know why we want this, so I don’t want to explain it further.

But how can we find out at runtime that Animal* is actually Dog* ? The fact is that we do not need to know what it is, we only need to know which functions to call or better to say which function pointer to call. All pointers to functions of virtual functions are stored in a virtual table for each class. You can imagine this as a "benchmark" on which the code calls a virtual function, depending on the actual class.

This virtual table is created at compile time (the compiler writes "recommendations" to the executable file), and each instance points to one of the available virtual tables. Therefore, if you say Dog *dog = new Dog , this points to the virtual table Dog. A call like dog->sayHello() compiles into a virtual call to the virtual sayHello function in a class that is not yet specified ...

Then, at run time, a call like dog->sayHello() first searches for a specific virtual table stored in the object (the code does not know that it is a dog, just that it is Animal) and finds a pointer to the Dog::sayHello() function.

To answer your question, this mechanism is called run-time polymorphism , because we can call methods that overload this pointer (which means that they overload the type of object you are calling), while the decision is made at runtime. You can cause peer matching polymorphism, where the compiler can know a specific type of object, for example, in Dog dog; dog.sayHello() Dog dog; dog.sayHello() .

0
source

Although it is true that a v-table is created at compile time, when the following code is compiled, the compiler does not know which function will be called:

 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 compilation time and runtime, the B :: f method is only selected at runtime because the compiler does not know the dynamic type of the object (which determines which method to call).

0
source

All Articles