据我了解,override
在 C++11 中引入关键字无非是检查以确保正在实现的函数是基类中函数的override
ing 。virtual
是这样吗?
据我了解,override
在 C++11 中引入关键字无非是检查以确保正在实现的函数是基类中函数的override
ing 。virtual
是这样吗?
确实是这样的想法。关键是您要明确说明您的意思,以便可以诊断出其他无声的错误:
struct Base
{
virtual int foo() const;
};
struct Derived : Base
{
virtual int foo() // whoops!
{
// ...
}
};
上面的代码可以编译,但不是您的意思(注意缺少的const
)。如果您改为使用virtual int foo() override
,那么您将收到编译器错误,表明您的函数实际上并未覆盖任何内容。
维基百科引用:
覆盖特殊标识符意味着编译器将检查基类以查看是否存在具有此确切签名的虚函数。如果没有,编译器会出错。
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
编辑(试图改进一点答案):
将方法声明为“覆盖”意味着该方法旨在重写基类上的(虚拟)方法。重写方法必须与它打算重写的方法具有相同的签名(至少对于输入参数)。
为什么这是必要的?好吧,防止了以下两种常见的错误情况:
一个人在新方法中打错了一个类型。编译器不知道它打算编写以前的方法,只是将其作为新方法添加到类中。问题是旧方法仍然存在,新方法只是作为重载添加。在这种情况下,对旧方法的所有调用都将像以前一样运行,而不会改变行为(这本来就是重写的目的)。
忘记将超类中的方法声明为“虚拟”,但仍试图在子类中重写它。虽然这显然会被接受,但行为不会完全符合预期:该方法不是虚拟的,因此通过指向超类的指针访问将结束调用旧的(超类')方法而不是新的(子类')方法。
添加“覆盖”清楚地消除了这一点:通过这个,一个人告诉编译器期待三件事:
如果其中任何一个为假,则发出错误信号。
* 注意:输出参数有时是不同的,但相关的类型。如果有兴趣,请阅读协变和逆变转换。
当有人更新基类虚拟方法签名(例如添加可选参数)但忘记更新派生类方法签名时,发现“覆盖”很有用。在这种情况下,基类和派生类之间的方法不再是多态关系。如果没有覆盖声明,很难找出这种错误。
是的,就是这样。这是一项检查,以确保不会尝试覆盖并通过拙劣的签名将其搞砸。这是一个 Wiki 页面,详细解释了这一点,并有一个简短的说明性示例:
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
C++17 标准草案
在浏览了C++17 N4659 标准草案的所有override
命中后,我能找到的唯一参考标识符是:override
5 如果一个虚函数被 virt-specifier override 标记并且没有覆盖一个基类的成员函数,那么这个程序是非良构的。[ 例子:
struct B { virtual void f(int); }; struct D : B { virtual void f(long) override; // error: wrong signature overriding B::f virtual void f(int) override; // OK }
—结束示例]
所以我认为可能炸毁错误的程序实际上是唯一的效果。
澄清关于虚拟的一切(因为我一直在反复遇到这个问题!)。
virtual
是为了基类告诉派生类一个函数可以被覆盖
virtual
在派生类中使用。如果一个函数具有相同的名称/参数类型 list/cv-qual/ref-qual,它将自动正确使用。virtual
在派生类中使用会产生细微的错误,见下文)override
是派生类捕获错误和文档代码
的可选说明符:所以给出:
class base
{
public:
virtual int foo(float x);
};
这里将如何处理一些不同的覆盖:
// AUTOMATIC virtual function (matches original, no keywords specified)
int foo(float x) { ; }
// Re-specifying "virtual" uselessly (+ see pitfalls below)
virtual int foo(float x) { ; }
// Potential issues: it is unknown if the author intended this to be a
// virtual function or not. Also, if the author DID intend a match but
// made a mistake (e.g. use "int" for the parameter), this will create
// a subtle bug where the wrong function is called with no warning anywhere:
int foo(int x) { ; } // SUBTLE, SILENT BUG! int instead of float param
virtual int foo(int x) { ; } // SUBTLE, SILENT BUG! int instead of float param
// Better approach: use the 'override' identifier to
// make sure the signature matches the original virtual function,
// and documents programmer intent.
int foo(float x) override { ; } // Compiler checks OK + tells coder this is virtual
int foo(int x) override { ; } // COMPILE ERROR, caught subtle bug
virtual int foo(int x) override { ; } // COMPILE ERROR, caught subtle bug
// (and redundant use of "virtual")
最后(!),final
可以使用说明符代替,override
原因相同,但如果您不希望在派生类中进一步覆盖。