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();
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.