首页 文章

C中的相互类实例

提问于
浏览
4

这段代码有什么问题?这里我们有两个文件: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'lewardB.h的前向声明:16:注意:即使在定义类时声明析构函数也不会调用特定于类的操作符delete .

4 回答

  • 9

    您无法创建不完整类型的实例(编译器对该类一无所知!)

    您需要将函数的定义(A和B的构造函数)移动到一个C文件中,该文件可以包含两个头文件(如果遵循每个文件有一个类的约定,则可以包含在几个C文件中) .

    话虽如此,你写的代码有一个严重的问题:每个A创建一个B的实例,每个B创建和A的实例 . 你将最终得到一个无限递归,你最终会耗尽内存 .

    两个次要的挑剔:你不需要在调用delete之前测试指针是否为空(删除空指针是安全的),并且你需要更改你的包含保护(在全局命名空间中以下划线开头的名称是保留给实施) .

  • 2

    编辑:阅读 James McNellis 's answer first -- this is a code example of what you' d必须这样做 . 但递归是更重要的一点,他应该得到任何特定点的赞成 - 不是我:)

    您不能在此处使用内联函数,因为当您将内联声明为内联时,类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

    classB.h:在构造函数'B :: B()'中:classB.h:12:错误:无效使用不完整类型'struct A'

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

    classB.h:6:错误:'struct A'wardB.h的前向声明:在析构函数'virtual B :: ~B()'中:

    我认为这是同样的问题 . 它需要知道 A 是如何定义的,因此它知道要释放多少内存 .

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

  • 1

    简单的解决方案是将您的成员函数定义提取到行外并进入文件classA.cpp和classB.cpp . 从头文件中删除相互包含,然后将它们插入.cpp文件中 .

    Anywhere A或B不只是在名称中使用(也就是说,除了命名它的指针或引用类型之外),必须已经存在完整的类声明 . 使用您当前的包含/内联设计,一个或另一个必然不完整 . 通过将类实现拆分为.cpp文件,您可以在实例化类型A或B的对象之前正常完成声明 .

相关问题