覆盖[[noreturn]]虚函数

时间:2015-09-18 15:17:01

标签: c++ c++11 inheritance noreturn

[[noreturn]]属性可以应用于不打算返回的函数。例如:

[[noreturn]] void will_throw() { throw std::runtime_error("bad, bad, bad ...."); }

但是我遇到了以下情况(不,我没有设计这个):

class B {
public:
  virtual void f() { throw std::runtime_error(""); }
};

class D : public B {
  void f() override { std::cout << "Hi" << std::endl; }
};

我真的想将属性[[noreturn]]放在B::f()声明中。但是我不清楚派生类中的覆盖会发生什么。从[[noreturn]]函数成功返回会导致未定义的行为,如果覆盖也继承了该属性,我当然不希望这样做。

问题:通过覆盖[[noreturn] virtual void B::f(),我是否会继承[[noreturn]]属性?

我查看了C ++ 14标准,我无法确定属性是否被继承。

3 个答案:

答案 0 :(得分:8)

我已经通过了标准,并且没有任何迹象表明[[noreturn]]具体或更普遍的属性是&#34;继承&#34;通过覆盖功能。

很难证明是消极的,而且标准实际上并没有以这种方式声明这一点,但是,因为A::f()B::f()仍然是不同的函数并且描述了唯一的行为根据功能定义,我认为您可以将A::f()标记为[[noreturn]]

话虽如此,我无法想象在给定动态调度的情况下,编译器可以随后执行哪些有用的优化。

答案 1 :(得分:3)

考虑一下你实际在说什么:

class B
{
public:
    [[noreturn]] virtual void f() { throw std::runtime_error(""); }
};

当然,人类读者,可能还有编译器,会解释 这是一个“契约”,即“f()不会回来,我保证”

这应该适用于f()的覆盖,否则你就违反合同。

标准可能没有详细说明,但即使它有效,我也建议根据可读性来反对它。

答案 2 :(得分:2)

在实践中, g++ clangMSVC都不会将[[noreturn]]属性视为已继承

#include <iostream>

struct B {
public:
  [[noreturn]] virtual void f() { std::cout << "B\n"; throw 0; }
};

struct D : public B {
  void f() override { std::cout << "D\n"; }
};

int main() 
{
    try { B{}.f(); } catch(...) {}
    D{}.f();

    B* d = new D{};
    d->f();
}

为所有三个编译器输出“B”,“D”和“D”。