错误:没有合适的默认构造函数

Error: no appropriate default constructor

本文关键字:默认 构造函数 错误      更新时间:2023-10-16

无法编译以下内容。 这里有什么问题?

class B;
class A
{
public:
    void DoSomething()
    {
        ...
        B* myb = new B();
        ...
    }
};
class B
{ 
public:
B() {}
};

new B()需要类型的完整定义。仅向前申报是不够的。

这是有道理的。例如,谁说B甚至有一个公共默认构造函数?在知道B的完整定义之前,你不可能知道这一点。

你做前向声明是为了知道一些class B存在,尽管它还没有定义。在这种情况下,您甚至不需要这样做,因为class A中没有 B 类型的成员。

只需声明 doSomething 方法,并在定义B后定义它

class A {
    ...
    void doSomething(); // declared
    ...
};
class B {
    ...
};
// define doSomething after defining class B or in the .cpp source file
void A::doSomething() {
    B *myb = new B();
    ...
}

尽管通常您会使用头/源文件,因此将声明与定义分开会更实用。


编辑

如果 A 和 B 都相互引用,那么您需要在其中之一(或两者(中编写前向声明。

// A.h
class B;
class A {
    ...
    B *_myB;
};
// A.cpp
#include "B.h"
void A::doSomething() {
    _myB = new B();
}

// B.h
class A;
class B {
    ...
    A *_myA;
};
// B.cpp
#include "A.h"
void B::doSomething() {
    _myA = new A();
}

前向声明允许您具有指向该类型的指针,例如 B* 。但不是完整的B类型,因为B的大小是未知的,但B*与任何其他指针的大小相同。

您可以通过在头文件中包含另一个类来使其中一个类存储完整类型,但不能同时包含两个类。

无论如何,如果可以包含依赖的完整类型,那就没有意义了。然后A的实例将实例化一个成员B而该成员又将实例化其成员A,依此类推。

当您转发声明一个类型时,您是在告诉编译器存在这样的类型。但是编译器不知道该类型的大小或成员。

通常使用前向声明来中断循环依赖项。

class B;
class A
{
public:
    void DoSomething()
    {
        ...
        B* myb ;            ...
    }
};

这将起作用,因为您只有一个指向该类型的指针。

这里已经详细讨论了这个问题:前向引用用法

class B;

上面的声明(前向声明(将名称 B 引入编译器。在声明之后和定义出现之前,类型 B 是不完整的类型

不完整类型的使用受到限制。例如,可以将指针或引用定义为此类类型。但是,这是不可能的;

  • 创建该类型的对象(编译器不知道类的大小(
  • 访问该类型的成员(编译器不知道该类具有哪个成员(

在有问题的代码中;

B* myb = new B();

是在声明之后和定义之前。