0

I'm having hard time to understand why the code below print C::f2 instead of B::f2.

From Charles Bailey answer:

When a non-virtual function is called the implementation must use the static type of the object on which the function is being called to determine the correct function to call. A function stored in a vtable accessed by a vptr will be dependent on the dynamic type of the object, not any static type of a reference or pointer through which it is being accessed.

I'm a bit lost, Inside A::f1 there is a call to f2. How does the compiler know which method to call?

My assemption:

  1. The compiler somehow remmber that we are inside object of type C.
  2. The compiler check if C contain a non virtual method name f2. a. if yes, run it. b. use the object's pointer to access his vtbl and run the right f2.

Am I right?

struct A
{
    void f1()
    {
        f2();
    }
    virtual void f2()
    {
        cout<<"A::f2"<<endl;
    }
};
struct B:public A
{
    virtual void f2()
    {
        cout<<"B::f2"<<endl;
    }
};
struct C:public B
{
    void f2()
    {
        cout<<"C::f2"<<endl;
    }
};
int main()
{
    C c1;
    c1.f1();
    return 0;
}
Stav Alfi
  • 13,139
  • 23
  • 99
  • 171

1 Answers1

4

Every member function has an implicit this parameter. The static type of this inside f1 is always A * const. This is true for any member function. The static type of the implicit object parameter is the enclosing class where the function is defined.

The call inside f1 is resolved as this->f2(). Since this is a call via pointer, the function f2 is dispatched dynamically. This is despite the fact the f1 is not virtual, and will always be called by static dispatch.

By whatever mechanism the compiler uses (a VTable is an implementation detail, not mandated by the C++ standard itself), we get a call to C::f2.

So your assumptions need some revision, I'd say.


To answer your question as you specified in the comments. C::f2 is virtual. You may have omitted the virtual specifier when overriding it, but there is no "unvirtualising" it.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Without specifing @interjay comment, I don't understand how you conclude that `C::f2` will be called. If you are agree please right that down, it will be very helpful to understand. If you disagree, please explain more how you conclude that `C::f2` will be called. Thanks. – Stav Alfi Jul 13 '17 at 13:24
  • @StavAlfi - I do believe you completely skipped the second paragraph. A call **via pointer**. If the called member is a virtual function, it will be called dynamically. – StoryTeller - Unslander Monica Jul 13 '17 at 13:29
  • Okay, but C::f2 is not defined as virtual so C::f2 is not registered in C VTBL so calling f2 dynamically should call to B::f2. – Stav Alfi Jul 13 '17 at 13:33
  • 1
    @StavAlfi - This is where your understanding suffers. Once a function is defined as virtual *once*, it's virtual in every derived class. Even if the virtual specifier isn't repeated. – StoryTeller - Unslander Monica Jul 13 '17 at 13:35
  • And that is complelty answering my question :) I recommend you to add https://stackoverflow.com/a/1404843/806963 it to your answer. Thanks for all the help! – Stav Alfi Jul 13 '17 at 13:39
  • 1
    @StavAlfi - Yeah, I see now what the question was really about. – StoryTeller - Unslander Monica Jul 13 '17 at 13:41