Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide virtual function with non-virtual override

Having

#include <iostream>

using namespace std;

class A {
public:
    virtual void foo() {
        cout << "A" << endl;
    }
};

class B : public A {
public:
    void foo() {
        cout << "B" << endl;
    }
};

class C : public B {
public:
    void foo() {
        cout << "C" << endl;
    }
};

int main() {
    C c;
    B* b = &c;
    b->foo();

    return 0;
}

The output is C, but I expected B.

I didn't declare B::foo() with the virtual modifier, so I expect the function call to be determined by the static type (no polymorphism).

Why is C::foo() being called?

Is it possible to provide a non-virtual function in a derived class, that hides the virtual function in the base? What signature should the derived member function have so that b->foo() calls it, and not (b->*&A::foo)()

like image 995
sk1ll3r Avatar asked Jun 18 '14 12:06

sk1ll3r


1 Answers

The principle of virtual inheritance of a member function is is a direct consequence of the C++ Standard:

10.3/2: If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list , cv-qualification, and refqualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual.

So regardless of the level of inheritance, the function will be virtual in all the classes derived somehow from A. There is no need to put the keyword virtual.

The goal of this polymorphic approach is to ensure that you always call the appropriate function corresponding to the real idendity of your object, regardless the fact that you use a pointer to a base or a pointer to the real class of the object. This is why you obtain "C" !

In this related SO question I explain a trick to give the impression of removing virtuality at one single level, using multiple inheritance. However it can be done only for a single level (you should do it for the class of your base pointer).

*By the way, you could write pb->B::foo(); no need of *&.

like image 60
Christophe Avatar answered Oct 24 '22 02:10

Christophe