合法地调用纯虚函数

时间:2014-02-06 10:07:47

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

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

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

    virtual void method() = 0;
};

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

int main()
{
    Derived d;
}

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

但是,只是为了好玩,任何人都可以想出一种方法来调用一个不依赖于未定义行为的纯虚函数吗?

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

编辑:有几个答案的家伙,谢谢你,但我应该说清楚,我意识到对纯虚函数进行非虚拟调用是合法的(在某处提供定义) 。我更想知道法律中是否存在任何可能导致虚拟呼叫的聪明漏洞,因此很可能在没有定义的常见情况下崩溃。

例如,也许通过多重继承可以执行一些聪明的(合法的)强制转换,但最终会被称为“错误的”(未实现的)PV method(),这类事情。我只是觉得这是一个有趣的脑力激荡: - )

4 个答案:

答案 0 :(得分:5)

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

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

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

答案 1 :(得分:2)

取决于你的意思。这是一个成功编译的,但最有可能导致链接器错误:

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

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

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

Live example

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

答案 2 :(得分:2)

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

答案 3 :(得分:0)

从@ 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