Home > database >  Pointer to base virtual function vs direct call of base virtual function
Pointer to base virtual function vs direct call of base virtual function

Time:02-07

Why do these two behave differently?

(obj.*lpfn)();

vs

obj.Base::fn();

I know when we directly call virtual member function (obj.fn()) it will do a virtual dispatch(find correct 'fn' implementation for type of obj, and call it). But why does a pointer to member function call that is set to Base implementation((obj.*lpfn)()) lead to virtual dispatch, and why does the same expression, except directly called (obj.Base::fn()) not do virtual dispatch? If anything, I would expect them both to do call base implementation of Print function(no virtualization)

#include <iostream>
class Base {
public:
    virtual void Print() { std::cout << "Base::Print();\n"; }
};
class Derived : public Base {
public:
    void Print() override { std::cout << "Derived::Print();\n"; }
};
int main() {
    Derived d;
    auto lpfn = &Base::Print;
    (d.*lpfn)();
    d.Base::Print();
}

Output:

Derived::Print();
Base::Print();

CodePudding user response:

From the C standard:

[expr.call]/1 For a call to a non-static member function, the postfix expression shall be an implicit (12.2.2, 12.2.3) or explicit class member access (8.2.5) whose id-expression is a function member name, or a pointer-to-member expression (8.5) selecting a function member; the call is as a member of the class object referred to by the object expression... If the selected function is non-virtual, or if the id-expression in the class member access expression is a qualified-id, that function is called. Otherwise, its final overrider (13.3) in the dynamic type of the object expression is called; such a call is referred to as a virtual function call.

Thus, there are only two cases where virtual dispatch is not performed for a call of a non-static member function: 1) the function is not virtual to begin with, or 2) the function is named with a qualified name, as in obj.Base::fn(). In all other cases - including the case of calling via a pointer-to-member - the final overrider is called.

CodePudding user response:

But why does a pointer to member function call that is set to Base implementation((obj.*lpfn)()) lead to virtual dispatch

Because that's how the language is specified. Virtual dispatch is a useful tool, and so being able to use virtual dispatch through pointers to member functions is also useful.

why does the same expression, except directly called (obj.Base::fn()) not do virtual dispatch?

Because occasionally it's useful to be able to use static dispatch. And the way that the language was designed is that static dispatch can be done by specifying the static type with a qualified name.

There's no syntax in the language to use static dispatch through a pointer to virtual member function. I cannot tell you why that is, but I could guess that given that static dispatch of virtual function is rather rarely needed feature, and pointers to member functions are a rather rarely needed feature, it may be that their combination is so rarely needed that it wasn't really considered.

  •  Tags:  
  • Related