- In c++11 the
override
specifier protects from not overriding an intended virtual base function (because the signatures do not match). - The
final
specifier protects from unintentionally overriding a function in a derived class.
=> 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
- abstract
class B : A
hasprivate: virtual void fooHasBeenDone() = 0;
class C : B
implementsprivate: virtual void fooHasBeenDone() override { react(); }
- Now
class A
gets a newprivate: virtual void fooHasBeenDone();
- But the new
A::foo
could be something different than the originalB::foo
.
and a specific example
- abstract
class B : A
hasvirtual void showPath() = 0;
meaing a PainterPath class C : B
implementsvirtual void showPath() override { mPath.setVisible(); }
- Now
class A
gets a newvirtual void showPath();
meaning a file path - Now when A calls showPath(), B shows the painterPath instead of some file path.
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)
-Wsuggest-override
GCC option may help, see gcc.gnu.org/onlinedocs/gcc/Warning-Options.html – FbiB
"? It confuses, asB
cannot have instance due to purevirtual
. Also, whatPainterPath
has to do here? Your last statement is confusing. I suggest that instead of putting the actual code with constructors etc., just put the minimal part, which is independent & anyone can verify using ideone.com. You can also look at my answer & comment under it, if it doesn't satisfy what you need. – KnarB::showPath()
is having a same signature asA::showPath()
& hence do something with it. Well, as I have wrote in my answer, you may markA::showPath()
asfinal
while adding it & compile the code. Fix any errors & then removefinal
for the production. – Knar