【问题标题】:Legally invoking a pure virtual function合法地调用纯虚函数
【发布时间】:2014-03-03 04:59:26
【问题描述】:

我相信我们都见过由于导致调用纯虚函数的错误而崩溃的代码。一个简单的例子是这样的:

struct Base
{
    Base() { method(); }

    virtual void method() = 0;
};

struct Derived : Base
{
    void method() {};
};

int main()
{
    Derived d;
}

在这种情况下,Base 构造函数中对method() 的调用被 C++ 标准的第 10.4/6 节明确引用为未定义行为,因此我们最终崩溃也就不足为奇了。 (g++ 和 Clang 都对此发出警告,事实上,在这个例子中,g++ 的链接失败了,尽管 Clang 成功了。)

但是,只是为了好玩,谁能想出一种方法来调用不依赖于未定义行为的纯虚函数?

(我想你可能会争辩说,如果存在这样的方法,那么 C++ 标准就有缺陷,但我只是好奇……)

编辑:几个答案,谢谢,但我应该明确表示,我意识到对纯虚函数进行非虚调用是合法的(前提是某处存在定义) .我更想知道法律中是否有任何巧妙的漏洞可能导致虚拟通话,因此很可能在没有定义的常见情况下崩溃。

例如,也许通过多重继承可以执行一些巧妙的(合法的)转换,但最终会调用“错误的”(未实现的)PV method(),诸如此类。我只是觉得这是一个有趣的脑筋急转弯:-)

【问题讨论】:

  • 看起来是language-lawyer 标记的不错候选者,但您已经是 5 岁了。您可以考虑重新标记。
  • @Angew 好电话,已更改
  • 好吧,没有什么可以阻止你实现那个纯虚函数,然后从那个ctor上下文中调用它就好了。
  • 三个字:纯虚析构函数。谷歌一下。
  • @user2079303 是的。只要是= 0,它就是一个纯虚函数,并导致包含它的类是抽象的。

标签: c++ c++11 language-lawyer undefined-behavior pure-virtual


【解决方案1】:

取决于您对可能的含义。这是一个编译成功,但很可能导致链接器错误:

struct Base
{
    virtual void method() = 0;
};

struct Derived : Base
{
    void method() { Base::method(); };
};

int main()
{
  Derived d;
  d.method();
}

Live example

它可以编译是因为没有什么能阻止纯虚函数实际上也有一个主体。这可以在相同的翻译单元(在单独的定义中)或不同的翻译单元中提供。这就是为什么它是链接器错误而不是编译器错误 - 只是该函数在此处没有主体并不意味着它在其他地方没有主体。

【讨论】:

  • 你唯一不能做的就是在课堂声明旁边提供正文。 (即在= 0 部分之后)语法的东西。
  • @PlasmaHH 我知道,我追求的是“打电话给没有身体的人”。答案修改
【解决方案2】:

从@Angew 的回答中取出链接器错误。不确定这里发生的未定义行为...

struct Base
{
    virtual void method() = 0;
};

void Base::method(){}

struct Derived : Base
{
    void method() { Base::method(); };
};

int main()
{
  Derived d;
  d.method();
}

Live Demo

【讨论】:

  • 这不应该是对 Angews 答案的评论吗(就像 PlasmaHH 所做的那样?)
【解决方案3】:

非虚调用纯虚函数是完全合法的:

Derived d;
d.Base::method();

当然,这需要定义函数,而您的示例中并非如此。

【讨论】:

    【解决方案4】:

    纯虚函数可以有一个实现。最好的例子:纯虚析构函数必须有一个实现,因为当一个对象被销毁时,所有的析构函数都会被调用。

    【讨论】:

      猜你喜欢
      • 2011-08-06
      • 1970-01-01
      • 2012-03-20
      • 1970-01-01
      • 1970-01-01
      • 2012-01-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多