有一个复杂的程序不断抛出缺少的默认构造函数错误,经过多次修补,我发现完全相同的场景给出了相同的错误。这有什么问题?
class B;
class A
{
public:
A() {instance = new B;}
virtual ~A() {delete instance;}
private:
A*instance;
};
class B : public A
{
public:
B(){}
}
不能转发声明要在基类中使用的派生类?
有一个复杂的程序不断抛出缺少的默认构造函数错误,经过多次修补,我发现完全相同的场景给出了相同的错误。这有什么问题?
class B;
class A
{
public:
A() {instance = new B;}
virtual ~A() {delete instance;}
private:
A*instance;
};
class B : public A
{
public:
B(){}
}
不能转发声明要在基类中使用的派生类?
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 到底是什么?让基类实例化派生类确实有点不寻常。
您需要将 A 的构造函数的定义(但不是声明)放在 A 之外,在 B 的定义之后。在 A 中使用 B 是可以的,只要您不需要它是完整的(完全定义的) -new B
肯定会.
关于编译器如何向前看的 c++ 规则并不明显(例如,instance
即使成员在类中稍后定义,但可以在方法中使用,但不能使用稍后在同一源文件中定义的类) .
在这种情况下,问题(正如其他报告的那样)是编译时编译new B
器必须了解B
的不仅仅是它是一个类,它不会继续阅读该类A
以查看 a 到底是什么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
,但B
它是 的特化A
,因此当您创建实例时,B
您还将创建A
(的A
基础子对象)的实例B
。
这意味着要创建一个实例,A
您需要间接创建一个A
.
听起来很绕圈,不是吗?
使用此代码实例化A
(或B
)的实例将导致无限递归(即在大多数实现中出现奇怪的崩溃)。
不,因为派生类可能包含其他元素。所以你不能用它来用派生类对象初始化基类对象。