此代码有什么问题? 这里我们有两个文件:classA.h和classB.h
classA.h:
#ifndef _class_a_h_
#define _class_a_h_
#include "classB.h"
class B; //????
class A
{
public:
A() {
ptr_b = new B(); //????
}
virtual ~A() {
if(ptr_b) delete ptr_b; //????
num_a = 0;
}
int num_a;
B* ptr_b; //????
};
#endif //_class_a_h_
classB.h:
#ifndef _class_b_h_
#define _class_b_h_
#include "classA.h"
class A; //????
class B
{
public:
B() {
ptr_a = new A(); //????
num_b = 0;
}
virtual ~B() {
if(ptr_a) delete ptr_a; //????
}
int num_b;
A* ptr_a; //????
};
#endif //_class_b_h_
当我尝试编译它时,编译器(g ++)说:
classB.h:在构造函数'B :: B()'中:
classB.h:12:错误:无效使用不完整类型'struct A'
classB.h:6:错误:'struct A'的前向声明
classB.h:在析构函数'virtual B :: ~B()':
中classB.h:16:警告:在调用delete运算符时检测到可能的问题:
classB.h:16:警告:无效使用不完整类型'struct A'
classB.h:6:警告:'struct A'的前向声明
classB.h:16:注意:析构函数和类特定的运算符delete都不是
调用,即使它们是在定义类时声明的。
答案 0 :(得分:9)
您无法创建不完整类型的实例(编译器对该类一无所知!)
您需要将函数的定义(A和B的构造函数)移动到一个C ++文件中,该文件可以包含两个标头(如果您遵循每个文件有一个类的约定,则可以包含在多个C ++文件中)。
有人说过,你编写的代码有一个严重的问题:每个A创建一个B的实例,每个B创建一个A的实例。你将最终得到一个无限递归,你最终会耗尽内存。
两个次要的挑剔:你不需要在调用delete之前测试指针是否为空(删除空指针是安全的),并且你需要更改你的包含警戒(名称以下划线开头)全局命名空间保留给实现。)
答案 1 :(得分:2)
编辑:首先阅读 James McNellis 的回答 - 这是您需要做的代码示例。但递归是更重要的一点,他应该得到任何特定点的赞成 - 不是我:)
您不能在此处使用内联函数,因为当您将内联声明为内联时,类A和B的完整定义不可用。将它们声明为普通函数,你可以使用前向声明。
classA.h
#ifndef _class_a_h_
#define _class_a_h_
#include "classB.h"
class B; //????
class A
{
public:
A();
virtual ~A();
int num_a;
B* ptr_b;
};
#endif //_class_a_h_
classB.h
#ifndef _class_b_h_
#define _class_b_h_
#include "classA.h"
class B
{
public:
B();
virtual ~B();
int num_b;
A* ptr_a;
};
#endif //_class_b_h_
classes.cpp
#include "classA.h"
#include "classB.h"
A::A() {
ptr_b = new B(); //????
}
A::~A() {
if(ptr_b) delete ptr_b; //????
}
B::B() {
ptr_a = new A; //????
}
B::~B() {
if(ptr_a) delete ptr_a; //????
}
答案 2 :(得分:1)
classB.h:在构造函数'B :: B()'中:
classB.h:12:错误:无效使用 不完整类型'struct A'
A
未完全定义。你只给它一个原型(class A;
)。
classB.h:6:错误:转发声明 'struct A'
classB.h:在析构函数中是虚拟的 B ::〜B()”:
我认为这是同样的问题。它需要知道如何定义A
,因此它知道要释放多少内存。
重构代码以删除循环依赖项。 (A创建B,B创建A ...创建B,创建A,创建B ...)
答案 3 :(得分:0)
简单的解决方案是将您的成员函数定义提取到行外并进入文件classA.cpp和classB.cpp。从头文件中删除相互包含,然后将它们插入到.cpp文件中。
Anywhere A或B不只是在名称中使用(也就是说,除了命名其指针或引用类型之外),必须已经存在完整的类声明。使用您当前的包含/内联设计,一个或另一个必然不完整。通过将类实现拆分为.cpp文件,可以在实例化类型A或B的对象之前允许声明优雅地完成。