override
关键字仅用于检查实现的函数是否是覆盖基类中的virtual
函数。就这样吗?
override
关键字仅用于检查实现的函数是否是覆盖基类中的virtual
函数。这确实是个好主意。关键在于你要明确表达自己的意思,这样就可以诊断出本来无声的错误:
struct Base
{
virtual int foo() const;
};
struct Derived : Base
{
virtual int foo() // whoops!
{
// ...
}
};
上述代码可以编译通过,但可能不是你本意(注意缺少const
)。如果你改为写成virtual int foo() override
,那么编译器会报错,因为你定义的函数实际上没有覆盖任何内容。
explicit
类定义会做什么?我从未听说过。 - Christian Rauoverride
时意图就是这样做)比记住边角案例更可能,即复制不同原型函数中的函数没有通用性,只有像缺少const
或将char
写成int
之类的异常情况。 - legends2koverride
关键字最好的使用案例在这个答案中提到,它比较具有未来性而不是立即性。该答案建议将override
与virtual
方法一起使用。在未来,当一个人错误地更改了签名时,它的用处就会显现出来。 - iammilind维基百科引用:
"override"特殊标识符意味着编译器将检查基类,以查看是否存在具有此完全签名的虚函数。如果没有,则编译器将报错。
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
编辑(试图改善一下答案):
将一个方法声明为"override"意味着该方法旨在重写基类上的一个(虚)方法。重写方法必须具有与它打算重写的方法相同的签名(至少对于输入参数)。
这为什么是必要的呢?嗯,以下两种常见的错误情况被防止了:
新方法中拼错类型。编译器不知道它打算重写之前的方法,只是将其作为新方法添加到类中。问题是旧方法仍然存在,新方法只是作为重载添加。在这种情况下,所有调用旧方法的方式将像以前一样工作,行为不会发生任何变化(这本来是重写的目的)。
忘记在超类中声明方法为"virtual",但仍然尝试在子类中重写它。虽然这似乎被接受了,但行为不会完全符合预期:方法不是虚拟的,因此通过指向超类的指针进行访问将最终调用旧(超类)方法,而不是新(子类)方法。
添加"override"明确消除了歧义: 通过这个,你告诉编译器有三件事正在等待:
override
是发现此类问题的好方法,但良好的单元测试覆盖率也应该有所帮助。+1 - Disillusioned是的,确实如此。这是一种检查机制,以确保不会因签名错误而尝试覆盖并搞乱它。以下是一个维基页面,详细解释了这个机制,并提供了一个简短的示例:
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
C++17标准草案
在查看了C++17 N4659标准草案中所有关于override
的引用后,我只能找到一个与override
标识符有关的参考:
5 If a virtual function is marked with the virt-specifier override and does not override a member function of a base class, the program is ill-formed. [ Example:
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 }
— end example ]
我认为可能唯一的影响是错误程序被炸掉。
为了澄清所有有关虚拟的事情(因为我一直遇到这个问题!)。
virtual
是用于基类告诉派生类可以覆盖一个函数
virtual
。如果具有相同的名称/参数类型列表/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
,原因相同,但是当你想要在派生类中不再进行进一步的重写时使用。
override
作为普通标识符无法与override
限定符发生冲突,因为后者只能出现在一个位置,而前者在语法上永远无效。这正是他们设置这种方式的原因,以便在单个上下文中使override
和final
具有特殊含义,并在不剥夺用户以前可用的将它们用作普通标识符的能力的同时。 - underscore_d