How do polymorphism and member function pointers work?

I have the following code:

#include <iostream> using namespace std; class Base { public: virtual void WhoAmI() const; typedef void (Base::*WhoPtr)() const; }; class Derived : public Base { public: virtual void WhoAmI() const; }; void Derived::WhoAmI() const { cout << "I am the derived" << endl; } void Base::WhoAmI() const { cout << "I am the base" << endl; } int main() { Base::WhoPtr func = &Base::WhoAmI; Base theBase; (theBase.*func)(); Derived theDerived; (theDerived.*func)(); cin.get(); return 0; } 

Let's focus on the main thing:

 int main() { Base::WhoPtr func = &Base::WhoAmI; Base theBase; (theBase.*func)(); Derived theDerived; (theDerived.*func)(); cin.get(); return 0; } 

We have a local variable func that has the address Base::WhoAmI .

In addition, we have Base and Derived objects.

In line 2 we will name the pointed func from the base: (theBase.*func)() .

I understand so far.

2 lines after, we call this from the derived: (theDerived.*func)() .

He prints: I am the derived . Why?

Both WhoAmI are virtual , which means that the call depends on the pointed object , not the type.

the specified func object belongs to Base . Why does he print I am the derived instead of I am the base ?

+4
source share
3 answers

Why are you surprised. You have a pointer to a member function that points to a virtual function. If you took theDerived address, or a link to it, and initialized a Base* or a Base& with it, you expect ptrToBase->WhoAmI() call the functions in the derived class. This is, after all, why you use a virtual function to get you started. The same thing happens when you call a pointer to a member function. The expression &Base::WhoAmI gives a pointer to a (virtual) member function.

+1
source

The specified theDerived object. The selected Base::whoAmI , note that the method name contains a reference to the class (static), but not a reference to the object (dynamic). What virtual function to call is determined by the runtime of the object used as this for the method.

0
source

The whole point of virtual functions is that it is a runtime solution that is called based on the dynamic type of the object in question. This is very different from a non-virtual function call in which the compiler itself makes a decision based on the declared type of the object, regardless of what type the real runtime object belongs to.

To do this, each class has a virtual function table (vtable), which in all its instances has an implicit pointer at run time. Now when you create the Base instance, the vtable pointer of the instance will point to the vtable Base table. Similarly, an instance of Derived will have a pointer to Derived vtable.

In these two vtables in your example, there is only one entry for WhoAmI() , the pointer in Base vtable points to Base::WhoAmI() , and the pointer in Derived vtable points to Derived::WhoAmI() .

Therefore, when you call WhoAmI() , the runtime will look for a vtable from the object, and then a pointer to the function to be executed.

This suggests that, as you can see from the behavior you saw, a pointer to a member function is used: nothing more or less than the offset in the vtable! In your case, this offset is likely to be just zero, since WhoAmI() is the first and only entry in the vtable. When you call a function after the member function pointer, you give it the object from which vtable is viewed. And then the offset in the vtable (pointer to a member function) is used to load the pointer to the actual code that runs, as with any other virtual function call.

The only difference is that in a normal virtual function call, the compiler will know the exact offset at which to look for the function pointer by the name of the called function, when you use the pointer to the member function, this offset is provided at the time the pointer executes the member function.

0
source

Source: https://habr.com/ru/post/1493946/


All Articles