简体   繁体   中英

Pointer-to-member-function performs virtual dispatch?

I tried to execute the following code.

#include <iostream>

class Base
{
public:
    virtual void func()
    {
        std::cout<<"Base called"<<std::endl;
    }
};

class Derived: public Base
{
public:
    virtual void func()  override
    {
        std::cout<<"Derived called"<<std::endl;
    }
};

int main()
{
    void (Base::*func_ptr)()=&Base::func; //Yes, the syntax is very beautiful.
    Base* bptr=new Derived();
    (bptr->*func_ptr)();
}

My expected output was Base called . However, Instead, the output was

Derived called

Which surprised me, because I think that func_ptr should be able to see only Base members(because I thought that func_ptr doesn't access the member function via _vptr , but the function address itself.

I would like to know, how the virtual dispatch takes place in this case(how the access to virtual table takes place), and where this behavior is defined in C++ standard(I couldn't find anything)?

Refer to [expr.call] , specifically here

[If the selected function is virtual], its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call

Whether you call the function through a pointer or by class member access is the same ( ref ); the actual function called for a virtual function ultimately depends on the actual type of the object it is being called on.

A few (non-normative) notes in the standard under [class.virtual] say much the same thing:

[Note 3: The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type)

[Note 4: [...] a virtual function call relies on a specific object for determining which function to invoke.


If you would like to know how the virtual function dispatch takes place, you will need to seek out a specific implementation, because the how is not standardized.

(I really enjoyed the article A basic glance at the virtual table , which shows one possible way you could implement it using C)

  1. Your understanding is incorrect.
  2. It is an implementation detail. Different compilers may implement it differently. If in doubt, look at the assembly . It is actually pretty clever in this particular compiler. If the value stored in the pointer-to-member is even, it is a straight function pointer (all functions are located at even addresses). If it is odd, it is an offset in the vtable, plus one. All vtable offsets are also even, so to get to the actual pointer, it is decremented by 1.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM