类的交叉引用(或头文件依赖与交叉包含)

注:类的交叉引用本身就是一种不好的设计,但是,有时我们又不得不这样用。


<一>问题
两种常见情况:
(1)直接相互引用
模型:
A.h中#include "B.h"
B.h中#include "A.h"


(2)传递式相互引用(或者叫环形)
模型:
A.h中#include "B.h"
B.h中#include "C.h"
C.h中#include "A.h"
B代表中间层,可以是多个


<二>现象

以下面的代码为例:

main.cpp

  1. #include <iostream>  
  2.   
  3. #include "class_a.h"  
  4. #include "class_b.h"  
  5.   
  6. int main()  
  7. {  
  8.     A aa;  
  9.     aa.InvokeB();  
  10.   
  11.     B bb;  
  12.     bb.InvokeA();  
  13. }  
class_a.h
  1. #ifndef CLASS_A_H  
  2. #define CLASS_A_H  
  3.   
  4. #include "class_b.h"  
  5.   
  6. class A  
  7. {  
  8. public:  
  9.     void InvokeB()  
  10.     {  
  11.         B *b;  
  12.         b->Print();  
  13.     }  
  14.   
  15.     void Print()  
  16.     {  
  17.         std::cout << "This is class A\n";  
  18.     }  
  19. };  
  20.   
  21. #endif  
class_b.h

  1. #ifndef CLASS_B_H  
  2. #define CLASS_B_H  
  3.   
  4. #include "class_a.h"  
  5.   
  6. class B  
  7. {  
  8. public:  
  9.     void InvokeA()  
  10.     {  
  11.         A *a;  
  12.         a->Print();  
  13.     }  
  14.   
  15.     void Print()  
  16.     {  
  17.         std::cout << "This is class B\n";  
  18.     }  
  19. };  
  20.   
  21. #endif  
错误现象:此处我们用#ifndef...#endif保护机制,导致编译器(VS2012)认为在class_b.h中,A仍然是未声明的标识符。

如果去掉这个保护机制,又会引起“重定义”或者“包含文件太多,深度=1024”等问题。


<三>解决办法

(1)提前声明
这个虽然可行,但是存在风险。这种方法切记不可使用类名来定义变量和函数的变量参数,只可用来定义引用或者指针。因为前导声明只是一个符号声明,不能知道实际对象的大小,引用的对象只能是指针类型

(2)挪动该类型定义
这个方法很容易想到,你不是说我使用前没声明嘛,那好啊,我直接把它代码搬到你那个#include前不就完了么。也就等于把顺序梳理了下。但这样会代码不大好看。

(3)抽出来放置于公共头文件
这个就相当于给新建了个安置地方,直接就把环给解了。



提前声明的例子:前导声明代替头文件依赖和交叉包含

1.头文件中使用前导声明替代交叉引用,由于前导声明只是一个符号声明,不能知道实际对象的大小,引用的对象只能是指针类型。

2.源文件中包含自己的头文件。

a.h

复制代码
class B;
class A
{
public:
A();
B
* b;
};
复制代码

b.h

复制代码
class A;
class B
{
public:
B();
A
* a;
};
复制代码

a.cpp

#include "A.h"
A::A()
{
}

b.cpp

#include "B.h"
B::B()
{
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值