3

我有一个Foo带有抽象方法的抽象基类,称为bar. 我barFoo的构造函数中调用。我期望子类被覆盖bar(毕竟它是抽象的),然后在每个实例上Foo调用被覆盖的:bar

class Foo
{
    public:
        Foo() { bar(); }
        virtual void bar() = 0;
}

但是,我收到一个错误:

foo.obj:-1: error: LNK2019: unresolved external symbol "protected: virtual void __cdecl Foo::bar(void)" (?bar@Foo@@MEAAXXZ) referenced in function "public: __cdecl Foo::Foo(void)" (??0Foo@@QEAA@XZ)

这种链接器错误通常意味着我已经定义了一些东西但没有声明它(或相反),这似乎又是这种情况。如果我添加这样的定义,一切都会正常工作bar

void Foo::bar() {}

这是预期的错误,还是链接器中的错误?如果是故意的,为什么会这样?我不明白为什么我不能从构造函数中调用抽象方法?我想到的唯一原因是在定义子类方法之前调用了基类的构造函数,但我仍然认为我不应该得到这个错误?

我在用着Qt Creator 2.7.0 - Based on Qt 5.0.2 (32 bit)

4

2 回答 2

4

在构造函数内部,是动态类型,*this没有Foo定义函数Foo::bar。不要在构造函数中调用虚函数。(除非您知道自己在做什么,在这种情况下您会知道如何提供定义。)

于 2013-05-15T20:30:26.287 回答
2

您的问题很简单,但又很困难:构造函数Foo在派生类的构造函数之前运行。因此,虚拟功能被设置为任何Foo设置 - 这是未实现的。

您必须等到构建完成才能按照您期望的方式使用虚函数,并且所有 vtable 条目都设置为它们最衍生的版本。

虽然可以将构造分为三个部分(首先由每个构造函数更新 vtable,然后执行所有初始化程序,最后执行所有构造函数),但 C++ 标准委员会已决定反对这样做。

除了编译器构建器的简单性之外,事情的完成方式也有一些优势:如果您可以访问更多派生的类成员(通过调用重写的virtual函数),它们就不会被初始化(甚至是构造),所以任何一个更派生类的函数不应该触及任何重要的数据成员,这比简单地说你不应该在构造过程中调用虚函数更加复杂。

于 2013-05-15T20:30:51.040 回答