在C++11中,在析构函数之后覆盖标识符

74

在虚析构函数声明后面加override标识符是否有特殊意义?

class Base
{
public:
    virtual ~Base()
    {}

    virtual int Method() const
    {}
};

class Derived : public Base
{
public:
    virtual ~Derived() override
    {}

    virtual int Method() override // error: marked override, but does not override - missing const
    {}
};

在虚拟方法上使用override标识符是有用的,因为它可以作为检查:当基类虚拟方法实际上未被覆盖时,编译器会报告错误。

虚拟析构函数上的override是否也有任何意义/功能?


2
编译器对此有何提示? - Nawaz
关于~Derived()覆盖,它并没有说明任何内容,编译也没有问题。我的意思是它是否有特殊含义。Method()覆盖当然是错误的,因为它缺少const。(我将其包含在示例中) - EnterTheNameHere Bohemian
7
如果基类不是虚拟的话,它将无法编译 - Nawaz
2个回答

61

是的。如果基类析构函数不是虚函数,那么使用override标记将导致程序无法编译:

class Base
{
public:
    ~Base()
    {}
};

class Derived : public Base
{
public:
    virtual ~Derived() override //error: '~Derived' marked 'override' but does
                                //        not override any member functions
    {}
};

21
需要同时使用 virtualoverride 吗?对于析构函数有特殊情况吗?传统智慧认为在正常方法中不要同时使用 virtualoverride,因为 override 使 virtual 失去了意义,但我不确定析构函数是否也是这样。 - Mark Lakata
1
个人意见是,这取决于特定组织和个人的编码约定。目前我出于习惯而同时使用两种方式。如果我出于习惯覆盖虚函数,我会添加虚拟限定符。即使在引入override关键字后,这种习惯仍然存在。 - leeor_net
1
@MarkLakata,它们仍然有不同的含义。如果您选择这样做,您可以覆盖父方法而无需将自己的方法设置为后代虚拟方法。 - yano
12
@yano,那不是真的。如果一个基类中声明了虚函数,那么在每个派生类中它默认都是虚函数。但是,你可以在派生类中使用虚函数来覆盖(shadow)而不是重写(override)一个非虚函数的基类方法。 - Balázs Kovacsics
1
@yano所谈论的是final关键字,它确保了一个方法在派生类中不能被重写,而它最初是一个虚拟方法。 - Pato Sandaña
@BalázsKovacsics和Pato,感谢你们的澄清/更正。 - yano

51

重点不在于关键字 override 本身,而是析构函数本身:

10.3 虚函数

6/虽然析构函数不会被继承,但在派生类中声明为虚拟的析构函数会覆盖基类的析构函数;请参见12.4和12.5。

如果将此与前面的内容结合起来看:

5/如果一个虚函数被标记为 override 并且没有覆盖基类的成员函数,则程序是非法的。[例如:

struct B { 
    virtual void f(int); 
}; 

struct D : B
{ 
    void f(long) override; // error: wrong signature overriding B::f
    void f(int) override; // OK 
}; 

您可以看到,如果一个析构函数被标记为override但基类没有virtual析构函数,那么程序将是不合法的。


1
不幸的是,VS2010会出现“error C3665:'MyClass ::〜MyClass':析构函数上不允许使用覆盖说明符'override'”的错误。也许在更现代的编译器中这种行为有所改进... - Tim MB
24
在基类中虚拟析构函数的情况下,是否建议在派生类中标记析构函数为override?Sutter和Meyers提供了清晰的指南,表明在覆盖虚成员函数时应使用override,但他们并没有专门讨论析构函数。我认为这样标记不会有坏处,但程序员们实际上会这么做吗? - Skeve
关于@TimMB的评论,FYI - VS 2017允许在派生类中覆盖虚拟析构函数。 - jschroedl
3
我在这里漏掉了什么吗?通常情况下,派生类中的析构函数不会像虚方法一样“覆盖”基类中的虚函数。它是互补的 - 当对象被拆除时,两个析构函数都会被调用。在我的看法中,使用override标记析构函数似乎完全是错误的。如果您使用非虚析构函数从基类派生,则应将程序视为格式不正确。 - David McCabe
我认为,如果你使用非虚析构函数从一个基类派生出来,程序应该被视为格式不正确。这是因为你预计通过一个基类指针进行派生类的多态使用。但是,在某些情况下,如果我们永远不会使用 Base* ptrBase = derivedPtr 这样的语句来操作 Derived 实例,那么拥有一个非虚基类析构函数也是完全合法的。 - Zoso
除非在VS2010中它是合法的,而且标准绝对没有明确说明它是合法的。我不明白为什么你会想要声明继承,而不能使用一个具有误导性的限定符来利用它。我希望这永远不会成为正统。编辑 - 来自这里看起来现在被认为是不好的做法。 - David McCabe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接