Search code examples
c++inheritanceoverridingvirtual

How to override a virtual function with a non-virtual function?


Refer to this question: Hide virtual function with non-virtual override

And this question: override on non-virtual functions

A function that overrides a virtual function is virtual too, even though it's not explicitly declared virtual.

My technical question is: Is there away to make that overriding function non-virtual (and applies that to classes lower in the hierarchy)? In other words, can I turn the "virtuality" off?

Obviously we can override a non-virtual function with a virtual function. Can we do the opposite, i.e. to override a virtual function with a non-virtual function?


Solution

  • You are looking for a way to overrride a virtual function, so that it is no longer virtual.

    Possible approaches using inheritance

    Unfortunately, you cannot get rid of the virtuality of the member function once it is declared virtual. This 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.

    The use of final will not solve your problem: it will just forbid you to override the function in more derived classes. The function will remain virtual.

    There is however an (unconvenient) trick to remove virtualisation at one specific level, using multiple inheritance:

    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; }
    };
    class EH {   // Helper class, does not derive from A 
    public:      // so foo() is non virtual here
        void foo() {   cout << "EH!" << endl; }
    };
    class E : public B, public EH { // inherits the virtual foo and the non virtual one
    public:
        using EH::foo;     // We just say to use the non virtual one
    };
    

    The class E inherits from both the virtual and the non virtual. We just say to use the non virtual one if one calls it:

    E e; 
    e.foo();          // calls the non virtual function EH::foo(); => EH!
    B* pb2 = &e; 
    pb2->foo();       // calls the original virtual function B::foo() => B
    

    Be aware that this trick works only for the current level: If you'd derive a class form E, the class would also inherit indirectly from A, and here is the virtual curse again !

    What do you intend to achieve ?

    With virtual functions, you 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. That's the goal of polymorphism.

    With non-virtual function, your compiler invokes the function he thinks is the correct one, according to the type you are accessing to. If you access the object via a valid base pointer it will hence use the function of the base class instead of the derived one. Is this really what you want ?

    if yes, just do this:

    C c;
    B* pb = &c;
    pb->foo();         // uses the virtual function
    pb->B::foo();      // but you can force to use the function, ignoring the virtuality.  
    

    Possible approach using a virtual and a non virtual function

    With little additional cost you could emulate this behaviour in your code, using a comibnation of 2 functions: a private virtual one, and a public non virtual:

    class A {
        virtual void foo2() { cout << "A" << endl; }  // virtual function
    public:  
        void foo() { foo2(); } // non virtual function calling the virtual one 
    };
    class B : public A {
        void foo2() { cout << "B" << endl; }  // overriding virtual
    };
    class C : public B { 
    public:
        void foo() { cout << "C" << endl; }   // ignore the virtual and override the non virtual function :-) 
    };