声明要在基类中使用的派生类会导致缺少默认构造函数错误

时间:2012-07-21 15:56:22

标签: c++

有一个复杂的程序不断抛出缺少的默认构造函数错误,并经过大量的修改后,我发现了完全相同的情况,给出了相同的错误。这有什么问题?

class B;

class A
{
public:
    A() {instance = new B;}
    virtual ~A() {delete instance;}
private:
    A*instance;
};

class B : public A
{
public:
    B(){}
}

无法转发声明要在基类中使用的派生类吗?

4 个答案:

答案 0 :(得分:2)

如果编译器对类new B一无所知,B如何成功呢?如果将成员函数实现移出类A,而不是类B的定义,那么它应该可以工作:

class A
{
public:
    A();
    virtual ~A();
private:
    A * instance;
};

class B : public A
{
public:
    B(){}
};

A::A()
{
    instance = new B;
}

A::~A()
{
    delete instance;
}

无论如何,A和B究竟是什么?让基类实例化派生类肯定有点不寻常。

答案 1 :(得分:0)

在B的定义之后,您需要将A的构造函数的定义(但不是声明)放在A之外。只要您不需要它完整(完全定义),在A中使用B就可以了 - 而new B肯定会。

答案 2 :(得分:0)

关于编译器将如何转发的c ++规则并不明显(例如,即使成员在类的后面定义但是使用类也不行,也可以在方法中使用instance。稍后在同一源文件中定义。)

在这种情况下,问题(正如其他报道的那样)是在编译new B时编译器必须知道更多关于B而不仅仅是一个类,并且它不会继续读取类A 1}}看看B究竟是什么。

一种可能的解决方案是稍后放置A构造函数和析构函数的定义(仍然让它们内联):

class B;

class A
{
public:
    A();
    virtual ~A();
private:
    A *instance;
};

class B : public A
{
public:
    B() {}
};

inline A::A() { instance = new B; }
inline A::~A() { delete instance; }

这会编译,但会无法正常运行,因为你在这里尝试做的确实非常困惑。

要创建A的实例,您要创建B的实例,但BA的特化,因此当您创建{的实例时{1}}您还将创建BA的{​​{1}} 基础子对象)的实例。

这意味着要创建A的实例,您需要间接创建B的实例。

听起来很吵,不是吗?

使用此代码实例化A(或A)的实例将导致无限递归(即大多数实现中的奇怪崩溃)。

答案 3 :(得分:-1)

没有。因为派生类可能包含其他元素。所以你不能用它来用派生类对象初始化基类对象。