-2

In the following snippet, foo() is not called directly via the Base class pointer (so that dynamic binding kicks in), but is called from a member function. Why is the derived class version still called?

#include <iostream>

struct Base{
    void run(){
        std::cout << "Base run" << "\n"; 
        foo();
    }
    virtual void foo(){
        std::cout << "Base foo" << "\n"; 
    };
};

struct Derived : Base{
    void foo() override{
        std::cout << "Derived foo" << "\n"; 
    }
};

int main(){
    Derived d;
    Base* ptr = &d;
    ptr->run();
}

Output:

base run
Derived
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
CD86
  • 979
  • 10
  • 27
  • 4
    `foo();` is actually `this->foo();` and `this` points to a `Derived`, not a `Base`. – NathanOliver Apr 05 '23 at 12:16
  • 1
    You might want a [better book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282) - that's not how virtual dispatch is determined. – molbdnilo Apr 05 '23 at 12:46
  • fwiw, that this works like it does is the basis of the [template method pattern](https://en.wikipedia.org/wiki/Template_method_pattern). (the name is unfortunate, because it has nothing to do with c++ templates) – 463035818_is_not_an_ai Apr 05 '23 at 14:00

2 Answers2

3

Virtual functions are called by searching their pointers in the table of virtual function pointers. As the pointer ptr points to an object of the derived class then the table of virtual function pointers referenced in the derived class is used and there is a pointer to the virtual function defined in the derived class in the table. So the virtual function in the derived class is called.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
3

There is an implied this-> in all member accesses, so the binding is dynamic and depends on the runtime type of the object.

You can avoid it by making the scope specific.

Example:

#include <iostream>

struct Base{
    void run(){
        std::cout << "Base run" << "\n"; 
        foo(); // Same as this->foo();
    }
    void run2(){
        std::cout << "Base run2" << "\n"; 
        Base::foo(); // Same as this->Base::foo();
    }
    virtual void foo(){
        std::cout << "Base foo" << "\n"; 
    };
};

struct Derived : Base{
    void foo() override{
        std::cout << "Derived foo" << "\n"; 
    }
};

int main(){
    Derived d;
    Base* ptr = &d;
    ptr->run();
    ptr->run2();
}

Output:

Base run
Derived foo
Base run2
Base foo
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • thanks for this clear explanation. Is the this-pointer within objects referring to the base or the derived objects generally? – CD86 Apr 05 '23 at 14:20
  • It points to the base subobject of the derived object. – molbdnilo Apr 05 '23 at 14:26
  • so if I understood correctly it like: Base * const this = &Derived; this->foo(); would it not be more accurate to say then that this is a const pointer to Base that points to Derived? Because if this would point to Base, virtual dispatch would not kick in right? – CD86 Apr 06 '23 at 08:22
  • The type of the *pointer* is `Base*`, and it points to the `Base` part of a `Derived` instance. The `Base` part contains all the information about which virtual function to call whatever the runtime type is. – molbdnilo Apr 06 '23 at 08:53