override
specifier protects from not overriding an intended virtual base function (because the signatures do not match).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
class B : A
has private: virtual void fooHasBeenDone() = 0;
class C : B
implements private: virtual void fooHasBeenDone() override { react(); }
class A
gets a new private: virtual void fooHasBeenDone();
A::foo
could be something different than the original B::foo
.and a specific example
class B : A
has virtual void showPath() = 0;
meaing a PainterPathclass C : B
implements virtual void showPath() override { mPath.setVisible(); }
class A
gets a new virtual void showPath();
meaning a file pathOf 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)
The facility of specifiers like first
or no_override
is not there as such. Probably because it may create confusion. However, it can trivially be achieved by changing the approach.
One should add any new method in the base class with final
specifier. This will help to get the compiler error for any matching signatures. Because, it will make the subsequent derived class method signatures automatically as "first" of their kind. Later the final
keyword can be removed, as it was intended just for "first hand verification".
Putting & removing final
keyword after the newly added base method is analogically similar to compiling binary with debug (g++ -g
) option, which helps you to fix bug. In production that debug option is removed for optimization.
From your example:
class A {}; // no method, no worry
class B {
public: virtual void showPath() = 0; // ok
};
...
Now accidentally you are adding similar method in A
, that results in error:
class A {
public: virtual void showPath() final; // same signature by chance
// remove the `final` specifier once the signature is negotiated
};
class B {
public: virtual void showPath() = 0; // ERROR
};
So the signatures between new A::showPath()
& existing B::showPath()
have to be negotiated & then carry on by removing final
specifier.
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.
first
or no_override
. (answer)
override
specifier as often as possible.Q_DECL_OVERRIDE
that expands to override
, if available.override
:-Winconsistent-missing-override
, and newer GCCs have -Wsuggest-override
."final
to any new virtual function. (answer)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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With