c++c++11inheritanceclass-hierarchymodifiers

What is the opposite of c++ `override` / `final` specifier?


=> Is there a specifier (something like maybe first or no_override) that protects from overriding an unknown base function?

I'd like to get a compiler error when a virtual function was added to a base class with the same signature as an already existing virtual function in a derived class.


EDIT 4: To keep this question simple and answers relevant, here is again the

original pseudo-code


and a specific example

Of course this is wrong, and I should then rename B::showPath() to B::showPainterPath() and implement B::showPath() override as well. I'd just like to get informed by the compiler.


Here is a compiling real-world example:

#include <iostream>
#define A_WITH_SHOWPATH

class A
{
#ifdef A_WITH_SHOWPATH
public:
    void setPath(std::string const &filepath) {
        std::cout << "File path set to '" << filepath << "'. Display it:\n";
        showPath();
    }
    // to be called from outside, supposed to display file path
    virtual void showPath() {
        std::cout << "Displaying not implemented.\n";
    }
#else
    // has no showPath() function
#endif  
};

class B : public A
{
public:
    virtual void showPath() = 0; // to be called from outside
};

class C1 : public B {
public:
    virtual void showPath() override {
        std::cout << "C1 showing painter path as graphic\n";
    }
};

class C2 : public B {
public:
    virtual void showPath() override {
        std::cout << "C2 showing painter path as widget\n";
    }
};


int main() {
    B* b1 = new C1();
    B* b2 = new C2();

    std::cout << "Should say 'C1 showing painter path as graphic':\n";
    b1->showPath();
    std::cout << "---------------------------\n";
    std::cout << "Should say 'C2 showing painter path as widget':\n";
    b2->showPath();
    std::cout << "---------------------------\n";

#ifdef A_WITH_SHOWPATH
    std::cout << "Should give compiler warning\n or say \"File path set to 'Test'. Display it:\"\n and \"Displaying not implemented.\",\n but not \"C1 showing painter path as graphic\":\n";
    b1->setPath("Test");
    std::cout << "# Calling setPath(\"Test\") on a B pointer now also displays the\n#  PainterPath, which is not the intended behavior.\n";
    std::cout << "# The setPath() function in B should be marked to never override\n#  any function from the base class.\n";
    std::cout << "---------------------------\n";
#endif
    return 0;
}

Run it and look at the text output.


For reference, an older example with a specific use-case (PainterPath instance):

https://ideone.com/6q0cPD (link may be expired)


Solution

  • This answer is community wiki because it combines all other answers. Please upvote the specific answer that was helpful to you as well as this one.

    1. No, there is no specifier like first or no_override. (answer)
    2. You should use the override specifier as often as possible.
      Qt has a macro Q_DECL_OVERRIDE that expands to override, if available.
      If not available, at least mark each overriding function with a comment.
    3. If you do that, there are compiler flags that warn about a missing override:
      "Clang now has -Winconsistent-missing-override, and newer GCCs have -Wsuggest-override."
      I don't know of a VS2012 flag for this. Feel free to edit.
    4. You can mimic the desired behavior by adding a 'secret' that the base class cannot know. (answer)
      This is helpful in very specific use cases, but generally breaks the concept of virtuality (see comments to the other answers).
    5. If you don't own the base class and have a conflict (e.g. compiler warning), you will need to rename your virtual function in all derived classes.
    6. If you own the base class, you can temporarily add a final to any new virtual function. (answer)
      After the code compiles without errors, you know that no function of that name and signature exists in any derived class, and you can remove the final again.

    ... I think I'll start marking first virtual functions as DECL_FIRST. Maybe in the future there will be a compiler-independent way of checking this.