Karen Baghdasaryan
Karen Baghdasaryan

Reputation: 2271

Pointer-to-member-function performs virtual dispatch?

I executed the following code.

#include <iostream>

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

class Derived: public Base
{
public:
    virtual void func()  override
    {
        std::cout<<"Derived func 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 func called. However, Instead, the output was

Derived func 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)?

Upvotes: 12

Views: 862

Answers (2)

AndyG
AndyG

Reputation: 41092

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)

Upvotes: 11

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

  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.

Upvotes: 2

Related Questions