据我所知,在c++ 11中引入override关键字不过是检查,以确保正在实现的函数是基类中的虚函数的重写。
就是这样吗?
据我所知,在c++ 11中引入override关键字不过是检查,以确保正在实现的函数是基类中的虚函数的重写。
就是这样吗?
是的,是这样。这是一种检查,以确保有人不会试图重写,并通过拙劣的签名把事情搞砸。这里有一个Wiki页面详细解释了这一点,并有一个简短的说明性示例:
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
维基百科:
覆盖特殊标识符意味着编译器将检查基类,以查看是否存在具有此签名的虚函数。如果没有,编译器就会出错。
http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final
编辑(试图改进一下答案):
将一个方法声明为“override”意味着该方法打算重写基类上的(虚)方法。重写方法必须具有与其打算重写的方法相同的签名(至少对于输入参数而言)。
为什么这是必要的?好了,下面两种常见的错误情况都避免了:
one mistypes a type in the new method. The compiler, unaware that it is intending to write a previous method, simply adds it to the class as a new method. The problem is that the old method is still there, the new one is added just as an overload. In this case, all calls towards the old method will function just as before, without any change in behavior (which would have been the very purpose of the rewriting). one forgets to declare the method in the superclass as "virtual", but still attempts to re-write it in a subclass. While this will be apparently accepted, the behavior won't be exactly as intended: the method is not virtual, so access through pointers towards the superclass will end calling the old (superclass') method instead of the new (subclass') method.
添加"override"清楚地消除了歧义:通过这个,一个是告诉编译器需要做三件事:
在超类中有一个同名的方法 超类中的这个方法被声明为“virtual”(这意味着要重写)。 父类中的方法与子类中的方法(重写方法)具有相同的(input*)签名。
如果其中任何一个为假,则发出错误信号。
*注意:输出参数有时是不同的,但相关的类型。如果有兴趣,请阅读协变和逆变变换。
这就是我的想法。关键是你要明确你的意思,这样就可以诊断出一个无声的错误:
struct Base
{
virtual int foo() const;
};
struct Derived : Base
{
virtual int foo() // whoops!
{
// ...
}
};
上面的代码可以编译,但不是您想要的(注意缺少const)。如果你说virtual int foo() override,那么你会得到一个编译器错误,你的函数实际上没有覆盖任何东西。
发现“override”是有用的,当有人更新基类的虚方法签名,如添加可选参数,但忘记更新派生类的方法签名。在这种情况下,基类和派生类之间的方法不再是多态关系。如果没有覆盖声明,就很难发现这类错误。
c++ 17标准草案
在浏览了c++ 17 N4659标准草案上的所有覆盖点之后,我能找到的唯一关于覆盖标识符的参考是:
类的成员函数被标记为virt-说明符override且不重写 基类时,程序是病态形式的。(例子: 结构B { 虚空f(int); }; 结构体D: B { 虚拟无效f(长)覆盖;//错误签名覆盖B::f 虚拟无效f(int)覆盖;/ /好吧 } - end示例]
所以我认为可能炸毁错误的程序实际上是唯一的影响。
为了澄清关于虚拟的一切(因为我已经多次遇到这个问题!)
virtual is for the base class to tell derived classes a function can be overridden There is no need to use virtual in derived classes. If a function has the same name/parameter type list/cv-qual/ref-qual, it will automatically be used correctly. (actually, using virtual in derived classes can create subtle bugs, see below) override is an optional specifier for derived classes to catch errors & document code: Tells the compiler: "make sure there is an EXACT virtual function I am overriding" Avoids creating a DIFFERENT function signature by mistake that would cause a subtle bug (i.e. 2 slightly different functions that are meant to be the same) Tells coders this is overriding a virtual function
所以给出:
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")
Finally(!),出于同样的原因,可以使用最终的说明符代替重写,但是如果您不想在派生类中进一步重写的话。