override
specifier可以防止不覆盖预期的虚拟基本功能(因为签名不匹配)。final
specifier可以防止无意中覆盖派生类中的函数。 =>是否有一个说明符(类似于first
或no_override
)可以防止覆盖未知的基本函数?
当虚拟函数被添加到基类中时,我希望得到编译器错误,该基类具有与派生类中现有虚函数相同的签名。
编辑4 :为了使这个问题变得简单并且答案相关,这里又是
原始伪代码
class B : A
有private: virtual void fooHasBeenDone() = 0;
class C : B
实施private: virtual void fooHasBeenDone() override { react(); }
class A
获得了新的private: virtual void fooHasBeenDone();
A::foo
可能与原始B::foo
不同。和具体示例
class B : A
有virtual void showPath() = 0;
使用PainterPath class C : B
实施virtual void showPath() override { mPath.setVisible(); }
class A
获得一个新的virtual void showPath();
,意思是文件路径当然这是错误的,然后我应该将B::showPath()
重命名为B::showPainterPath()
并实施B::showPath() override
。我希望得到编译器的通知。
这是一个编译现实世界的例子:
#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;
}
运行它并查看文本输出。
供参考,具有特定用例(PainterPath实例)的旧示例:
https://ideone.com/6q0cPD(链接可能已过期)
答案 0 :(得分:2)
没有。
将虚函数添加到与子类中的虚函数具有相同签名的基类不能打破任何现有功能,除非添加该虚拟函数将基类转换为多态类型。因此,在常态中,它是良性的,并且最纯粹的人会争辩说,添加语言功能以防止这种情况将是毫无意义的。
(当然你可以标记你的新函数Id Name DisplayOrder
100 Home 1
101 Products 2
102 Contact 4
103 Career 3
只是为了检查一个子类函数是不是要破坏它。)
您唯一的选择是使用代码分析工具。
(请注意,VS2012没有实现,甚至声称实现了C ++ 11标准,尽管它确实有一些。)
答案 1 :(得分:2)
像first
或no_override
这样的说明符的设施不存在。可能是因为它可能会造成混乱。但是,通过改变方法可以很容易地实现。
应该使用final
说明符在基类中添加任何新方法。这将有助于为任何匹配的签名获取编译器错误。因为,它会使后续的派生类方法签名自动成为同类中的“第一”。之后 final
关键字可以删除,因为它仅用于“第一手验证”。
放置&amp;在新添加的基本方法类似于使用debug(final
)选项编译二进制文件之后删除g++ -g
关键字,这有助于您修复错误。在生产中,删除调试选项以进行优化。
从你的例子:
class A {}; // no method, no worry
class B {
public: virtual void showPath() = 0; // ok
};
...
现在我不小心在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
};
新A::showPath()
&amp;之间的签名现有的B::showPath()
必须经过谈判和然后通过删除final
说明符来继续。
答案 2 :(得分:2)
这个答案是社区维基,因为它结合了所有其他答案。请提供对您有用的具体答案以及此答案。
first
或no_override
等说明符。 (answer) override
说明符。 Q_DECL_OVERRIDE
会扩展为override
如果不可用,至少用注释标记每个覆盖功能。override
:-Winconsistent-missing-override
, and newer GCCs have -Wsuggest-override
.” final
添加到任何新的虚拟功能。 (answer) final
。 ...我想我会开始将第一个虚拟函数标记为DECL_FIRST
。也许在将来会有一种独立于编译器的方法来检查它。
答案 3 :(得分:1)
C ++似乎没有提供开箱即用的手段。但你可以模仿它如下:
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())
{
}
};
如果您打算引入 new 虚拟函数,请按以下方式执行:
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())
{
}
};