当前位置:C++技术网 > 资讯 > 类的前置声明的使用:循环引用和循环包含

类的前置声明的使用:循环引用和循环包含

更新时间:2015-06-24 18:20:51浏览次数:1+次

    类的前置和函数的前置声明很类似,就是在使用前,先前置声明一下类,在你的B类声明之前,B类就需要你的A类,而你的A类又需要引用B类,这样就造成了循环。如果使用常规方法,始终无法解决。C++中提供类的前置声明,解决了这个问题,这和函数的前置声明类似又有很大不同。如果不是循环引用,大可不必使用前置声明类。
    另外还有一种情况,那就包含头文件。A类和B类分别在两个头文件中,然后是相互包含头文件。如果在头文件包含对方的头文件,则出现了循环包含。比如先编译A,则先包含B的头文件,然而在展开B头文件时,又包含A,展开A,又展开B,又展开A,结果就陷入了循环展开,搞不清楚了。
    为了解决上述问题,则必须使用类的前置声明来解决。
    第一个情况是使用还是比较好理解的,和函数的前置声明类似。不过使用时,只能是对象指针,不能直接在类中声明类对象成员,而是类指针。然而,循环包含却是很麻烦的事。因为包含是一个展开动作,如果遇到头文件中包含了其他头文件,则继续展开,就这样,如果有循环则出大问题了。此时就不要使用相互包含了,只要在一个类中进行包含就可以了。另外一个就使用前置声明,这样保证两个类都可以正确的编译,也告诉编译器这两个类名都表示的是一个类。
    使用了前置类声明,避免了循环包含和循环引用的问题。这个使用,确实也是不得已而为之,一般不推荐这样用。

    错误代码示例:

//a.h头文件:A类的声明
------------------------------
#include "b.h"

class A
{
public:
    A();
    ~A();
    void testA(){}
public:
    B b;

};

//a.cpp实现文件:A类成员函数的实现
------------------------------
#include "a.h"

void A::testA()
{

}

//b.h头文件:B类的声明
------------------------------
#include "a.h"

class B
{
public:
    B();
    ~B();
    void testB(){}
public:
    A a;

};

//b.cpp实现文件:A类成员函数的实现
------------------------------
#include "b.h"

void B::testB()
{

}

    就这样编译的话,会报错如下:

1>e:测试项目testtestb.h(2) : fatal error C1014: 包含文件太多 : 深度 = 1024
1>e:测试项目testtesta.h(2) : fatal error C1014: 包含文件太多 : 深度 = 1024
     错误的意思就是循环包含了,当到达IDE设定的最大深度时,则认为是循环错误了。这个是用来检测循环包含的问题。这个错误就是典型的循环包含。

    此问题的解决方案就是:

    在头文件中,使用类的前向声明,然后,在头文件中只能使用前向声明类的类来声明指针,不能声明类对象,否则报错。然后再cpp文件中,如果A类的函数要使用B类的东西,则在A类的Cpp文件中,包含b.h即可,要在B类的Cpp中使用A类的东西,则要在B类的Cpp中包含b.h。这样就解决了问题。因为是类指针,在生成对象时,这个成员是有固定的内存大小的,即4字节,完全可以编译通过,只是A,B是一个字符,要让编译器知道这个是类名,就需要前置声明。之后再使用前,即在Cpp文件中,包含对应的类头文件,这样就可以在Cpp中new一个对象了。而在类头文件中直接声明前向声明的类对象,因为是前向声明,并不知道这个类的具体大小,因此无法分配内存,导致错误,即使前向声明的类,也是不能直接声明对象,而只能是指针,否则编译报错。这个即使前置声明的类在同一个头文件中,也是如此。大家可以测试一下。

    正确的代码如下:

//a.h头文件:A类的声明
------------------------------
class B;
class A
{
public:
    A();
    ~A();
    void testA(){}
public:
    B* pB;

};

//a.cpp实现文件:A类成员函数的实现
------------------------------
#include "a.h"
#include "b.h"
void A::testA()
{
    pB = new B;
}


//b.h头文件:B类的声明
------------------------------
class A;
class C;
class B
{
public:
    B();
    ~B();
    void testB(){}
public:
    A *pA;
    C * pC;//此时也不能是C c;这样会报错
};
class C
{
};

//b.cpp实现文件:A类成员函数的实现
#include "b.h"
//此函数并没有newA的对象,无需包含A头文件
void B::testB()
{

}