[英]What is the opposite of c++ `override` / `final` specifier?
override
specifier protects from not overriding an intended virtual base function (because the signatures do not match). 在c ++ 11中, override
说明符可以防止不覆盖预期的虚拟基本函数(因为签名不匹配)。 final
specifier protects from unintentionally overriding a function in a derived class. final
说明符可防止无意中覆盖派生类中的函数。 => Is there a specifier (something like maybe first
or no_override
) that protects from overriding an unknown base function? =>是否有一个说明符(类似于first
或no_override
)可以防止覆盖未知的基本函数?
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 编辑4 :为了使这个问题简单并且答案相关,这里又是
original pseudo-code 原始的伪代码
class B : A
has private: virtual void fooHasBeenDone() = 0;
抽象class B : A
有private: virtual void fooHasBeenDone() = 0;
class C : B
implements private: virtual void fooHasBeenDone() override { react(); }
class C : B
实现private: virtual void fooHasBeenDone() override { react(); }
private: virtual void fooHasBeenDone() override { react(); }
class A
gets a new private: virtual void fooHasBeenDone();
现在, class A
获得一个新的private: virtual void fooHasBeenDone();
A::foo
could be something different than the original B::foo
. 但是新的A::foo
可能与原始的B::foo
。 and a specific example 和一个具体的例子
class B : A
has virtual void showPath() = 0;
抽象class B : A
具有virtual void showPath() = 0;
meaing a PainterPath 使用PainterPath class C : B
implements virtual void showPath() override { mPath.setVisible(); }
class C : B
实现virtual void showPath() override { mPath.setVisible(); }
virtual void showPath() override { mPath.setVisible(); }
class A
gets a new virtual void showPath();
现在, class A
获得一个新的virtual void showPath();
meaning a file path 意思是文件路径 Of course this is wrong, and I should then rename B::showPath()
to B::showPainterPath()
and implement B::showPath() override
as well. 当然这是错误的,然后我应该将B::showPath()
重命名为B::showPainterPath()
并实现B::showPath() override
。 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): 作为参考,具有特定用例(PainterPath实例)的旧示例:
https://ideone.com/6q0cPD (link may be expired) https://ideone.com/6q0cPD (链接可能已过期)
No there is not. 不,那里没有。
Adding a virtual function to a base class that has the same signature as a virtual function in a child class cannot break any existing functionality unless adding that virtual function turns the base class into a polymorphic type . 将虚函数添加到与子类中的虚函数具有相同签名的基类不能破坏任何现有功能, 除非添加该虚函数将基类转换为多态类型 。 So in the norm, it's benign, and a purest would argue, adding language features to guard against this would be rather pointless. 因此,在常态中,它是良性的,并且最纯粹的人会争辩,添加语言功能以防止这种情况将是毫无意义的。
(Of course you could mark your new function final
just to check that a child class function isn't going to clobber it.) (当然你可以将你的新函数标记为final
,以检查子类函数是否会破坏它。)
Your only option is to resort to code analysis tools. 您唯一的选择是使用代码分析工具。
(Note that VS2012 does not implement, or even claim to implement, the C++11 standard, although it does have some of it.) (请注意,VS2012没有实现,甚至声称实现了C ++ 11标准,尽管它确实有一些。)
The facility of specifiers like first
or no_override
is not there as such. 像first
或no_override
这样的说明符的工具不存在。 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 . 应该使用final
说明符在基类中添加任何新方法 。 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". 稍后可以删除final
关键字 ,因为它仅用于“第一手验证”。
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. 在新添加的基本方法之后放置和删除final
关键字类似于使用debug( g++ -g
)选项编译二进制文件,这有助于您修复错误。 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: 现在我不小心在A
中添加了类似的方法,导致错误:
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. 因此,必须协商新的A::showPath()
和现有的B::showPath()
之间的签名,然后通过删除final
说明符来继续。
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. 请upvote特定的答案,这对你和这个有帮助。
first
or no_override
. 不,没有像first
或no_override
这样的说明no_override
。 (answer) (回答) override
specifier as often as possible. 您应该尽可能频繁地使用override
说明符。 Q_DECL_OVERRIDE
that expands to override
, if available. Qt有一个宏Q_DECL_OVERRIDE
,如果可用,它会扩展为override
。 override
: 如果你这样做,有一些编译器标志警告缺少override
: -Winconsistent-missing-override
, and newer GCCs have -Wsuggest-override
. " “ Clang现在有-Winconsistent-missing-override
,而较新的GCC有-Wsuggest-override
。 ” final
to any new virtual function. 如果您拥有基类,则可以临时向任何新虚函数添加final
。 (answer) (回答) final
again. 代码编译后没有错误,您知道任何派生类中都不存在该名称和签名的功能,您可以再次删除该final
。 ... I think I'll start marking first virtual functions as DECL_FIRST
. ...我想我会开始将第一个虚拟函数标记为DECL_FIRST
。 Maybe in the future there will be a compiler-independent way of checking this. 也许在将来会有一种独立于编译器的方法来检查它。
C++ doesn't seem to provide such means out of the box. C ++似乎没有提供开箱即用的手段。 But you can mimic it like follows: 但你可以模仿它如下:
template<class Base>
class Derived : public Base
{
private:
struct DontOverride {};
public:
// This function will never override a function from Base
void foo(DontOverride dummy = DontOverride())
{
}
};
If you intend to introduce a new virtual function, then do it like below: 如果您打算引入新的虚函数,请执行以下操作:
template<class Base>
class Derived : public Base
{
protected:
struct NewVirtualFunction {};
public:
// This function will never override a function from Base
// but can be overriden by subclasses of Derived
virtual void foo(NewVirtualFunction dummy = NewVirtualFunction())
{
}
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.