在C ++ 11之前,当在派生类中重写虚函数时,建议将virtual关键字也添加到派生类函数中以使意图清晰。
现在这样的功能被标记为“覆盖”,其中包括必须存在虚拟基本功能的概念。因此我现在更喜欢省略虚拟:
class Derived: public Base {
public:
void Overriden() override;
// Instead of: virtual void Overriden() override;
};
然而,这会导致MSVC 2012中的IntelliSense错误: 'override'修饰符需要一个带有显式'virtual'关键字的虚函数声明
显然编译器会编译类,但错误让我想到了它。是否仍有正当理由添加虚拟关键字?
答案 0 :(得分:3)
override
关键字报告的,其含义是手头的函数必须覆盖虚函数:
在方法声明中,override指定该函数必须是 覆盖基类方法。
这是强制执行(即使编译器强制执行)此类要求的手段。当然,如果基类的函数不是虚函数,代码将无法编译。因此,正如您所指出的,添加虚拟是多余的。
我认为在c ++ 11之前添加它并不是一个好建议。请考虑以下代码段:
#include <iostream>
using namespace std;
class A{
public:
void f(){
cout << "A" << endl;
}
};
class B : public A{
public:
virtual void f(){
cout << "B" << endl;
};
};
class C : public B{
public:
void f(){
cout << "C" << endl;
};
};
int main( int argc, char* argv[] )
{
C c;
A& aref = c;
aref.f();
B& bref = c;
bref.f();
}
其输出显然是“A”,后跟“C”。如您所见,在virtual
中添加class C
根本不会产生任何影响,而virtual
中的class B
则起着关键作用。遵循将virtual
添加到class C
的约定会让人更难以一目了然。
答案 1 :(得分:1)
我认为这更像是品味问题: - )
我更喜欢只在定义后面写覆盖,这意味着该函数已经是虚拟的。程序员根据定义是懒惰的,所以保持简短的源: - )
我们在编码指南中添加了一条规则,其中覆盖是必须的,虚拟应该在正常更改过程中或在重构实际类时从旧代码中删除。
但这只是我们的解决方案,而且没有技术原因!
答案 2 :(得分:0)
是的,在覆盖基类行为时,您应该更喜欢使用virtual
而不是#include <iostream>
using namespace std;
class Base {
public:
virtual void foo() {
std::cout << "BASE foo" << std::endl;
}
void bar() {
std::cout << "BASE bar" << std::endl;
}
};
class A : public Base{
public:
void foo() override {
std::cout << "A foo" << std::endl;
}
virtual void bar() {
std::cout << "A bar" << std::endl;
}
};
class B : public A {
public:
void bar() override {
std::cout << "B bar" << std::endl;
}
};
int main(int argc, char *argv[])
{
B b;
A *a = &b;
Base *base = &b;
base->foo();
a->foo();
base->bar();
a->bar();
return 0;
}
。因为它可能导致可能的错误
这怎么可能导致错误? 这是一个例子,
A foo
A foo
BASE bar
B bar
输出将是
foo()
bar
被正确覆盖,但bar()
未被覆盖,并且在某些情况下会被隐藏。即使基础对象是相同的
override
的调用也不会调用相同的方法
如果我们强制要求在覆盖时始终使用virtual
而在void bar() override {}
仅定义新的虚拟函数,那么当我们尝试error: ‘void A::bar()’ marked ‘override’, but does not override
时,编译器会抱怨{{1}}
这正是Autosar specification定义以下规则
的原因规则A10-3-1(必需,实施,自动化) 虚函数声明应包含三个说明符中的一个:(1)虚拟,(2)覆盖,(3)最终。
理由: 指定这三个说明符中的多个以及虚函数声明是多余的,并且是潜在的错误来源。