2010-03-30 49 views
4

此代码有什么问题? 在这里,我们有两个文件:classA.h和classB.hC++中的相互类实例

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: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

classB.h:16: warning: possible problem detected in invocation of delete operator:

classB.h:16: warning: invalid use of incomplete type ‘struct A’

classB.h:6: warning: forward declaration of ‘struct A’

classB.h:16: note: neither the destructor nor the class-specific operator delete will be

called, even if they are declared when the class is defined.

+2

每当类此耦合的,您的设计可能需要一些重构前摆好完成。 – GManNickG 2010-03-30 01:52:22

+0

@GMan:与实施迭代器模式的一个例外,非常同意。 +1。 – 2010-03-30 01:53:29

回答

9

不能创建一个不完整的类型的实例(编译器不知道什么关于班级!)

您需要将函数的定义(A和B的构造函数)移动到可包含头文件的C++文件中(或者如果遵循约定,每个文件只有一个类,则可将其定义为多个C++文件)。

之前已经说过,你编写的代码有一个严重的问题:每个A创建一个B的实例,每个B创建一个A的实例。最终会有一个无限递归,最终会导致内存不足。

两个小问题:你不需要在调用delete之前测试一个指针是否为null(可以安全地删除一个空指针),并且你需要改变你的包含守护进程(名字以下划线开始全局命名空间保留给实现)。

+1

+1递归 – Rado 2010-03-30 01:47:58

2

编辑:请先阅读James McNellis的回答 - 这是您必须要做的一个代码示例。但递归是更大的一点,他值得任何upvotes为该特定点 - 不是我:)

您不能使用内联函数作为类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; //???? 
} 
+0

但是...寻找无限递归! – 2010-03-30 01:49:15

+0

@Drew厅:好一点 - 没想到这一点。但这里不会窃取詹姆斯麦克奈利斯的观点 - 他应该得到他们。 – 2010-03-30 01:49:55

+0

我认为它根本不起作用。你有没有试图自己编译它? – sepisoad 2010-03-30 02:22:28

1

classB.h: In constructor ‘B::B()’:

classB.h:12: error: invalid use of incomplete type ‘struct A’

A未完全定义。你只给它一个原型(class A;)。

classB.h:6: error: forward declaration of ‘struct A’

classB.h: In destructor ‘virtual B::~B()’:

认为这是同样的问题。它需要知道如何定义A,以便知道要释放多少内存。

重构代码以删除循环依赖项。 (A创建B,B创建A ...创建B,创建A,创建B ...)

0

简单的解决方案是将您的成员函数定义从线外拖入文件classA.cpp和classB.cpp。从头文件中删除相互包含,并将其插入到.cpp文件中。

Anywhere的A类或B用于不仅仅是在名称更多(即,不仅仅是其命名指针或引用类型除外),一个完整的类声明必须已经存在。使用目前的包含/内联设计,其中一个或另一个不一定完整。通过拆分类实现了到.cpp文件,您允许的声明类型为A的实例化对象或B.