How do I determine what a function will be called if it's virtual and when it is not?

Viewed 58

Look at this excerpt of a program.

I see that cout << obj->foo(); call is not polymorphic. Actually, it is obvious, because it has no virtual specificator.

But I am confused with cout << ((B*)obj)->foo(); Why the program does not use the B's definition of virtual function and will call the third version of foo()?

 #include <iostream> 
using namespace std; 

class A{ 
public:     
    int foo(){ return 1; } 
}; 
class B: public A{ 
public:     
    virtual int foo(){ return 2; } 
}; 
class C: public B{ 
public:     
    int foo(){ return 3; } 
}; 

int main() {  
    A* obj = new C; 

    cout << obj->foo(); 
    cout << ((B*)obj)->foo(); 
    cout << ((C*)obj)->foo(); 

    return 0;  
}
3 Answers

A::foo() is not virtual. Calling foo() via an A* pointer (or A& reference) will call A::foo() directly without any polymorphic dispatch.

B::foo() is virtual. Calling foo() via a B* pointer (or B& reference) will dispatch the call to the most derived implementation of foo() that exists in the object that the B* (or B&) refers to.

C derives from B, and C::foo() overrides B::foo(), and obj points to a C object, which is why C::foo() gets called by polymorphic dispatch when foo() is called via a B* or C* pointer (or a B& or C& reference).

Because ((B*)obj)->foo(); behaves by design like B* b = (B*)obj; b->foo() and calls C::foo. You may call the base's method explicitly like ((B*)obj)->B::foo();.

#include <iostream> 
using namespace std; 

class A{ 
public:     
    int foo(){ return 1; } 
}; 
class B: public A{ 
public:     
    virtual int foo(){ return 2; } 
}; 
class C: public B{ 
public:     
    int foo() override { return 3; } 
}; 

int main() {  
    A* obj = new C; 

    cout << obj->foo();
    cout << ((B*)obj)->B::foo(); 
    cout << ((C*)obj)->foo(); 

    return 0;  
}

Output: 123

Member function foo is virtual from class B downwards, i.e. also in C, even if it is not marked virtual or override there.

Thus, call ((B*)obj)->foo() is a virtual call, actually resulting in calling C::foo.

Related