huidong

首页 | 会员登录 | 关于争取 2022 寒假做出汇东网 Ver3.0.0 !
搜索文章


今天研究了很一会,终于稍微明白一点头文件的包含问题了……

背景

问题背景是:两个头文件对应两个 cpp,两个头文件声明的内容相互用到。


假设这两个头文件叫 A.h 和 B.h 吧!他们分别声明了类 A 和 B。并且两个类中分别用到对方。


这样的话,我当时就马上使用了最错误的方案:新建第三个头文件(比如叫 god.h),然后在 god.h 里面 #include 这两个头文件,最坏的是,我还在 A.h 和 B.h 中都去 #include "god.h"。最后,我在 main.cpp 中包含 god.h,从而十分“聪明地”构成了完美闭环,各个模块相互包含,似乎天衣无缝。


然而,这种做法大错特错……我们先假设每个头文件都设置了 #pragma once,按这样的包含关系,由于最后展开是线性的,所以一定有其中一个类会报错(比如 A 报错,就会显示 B 类未定义)。


我发现这样不行之后,就兴致勃勃地转向另一种方案:在 A.h 中包含 B.h,在 B.h 中包含 A.h,而 main.cpp 还是包含 god.h 不变。


这样又犯了相同的错误,AB 两个文件相互包含,最后肯定有一个展开在前面,有一个在后面,那么在前面的那个类就肯定会认为后面那个类未定义。

解决办法

假设 AB 两个类都只是用到对方的指针,那么就最好办。这个时候用再在 AB 的头文件里面包含对方了,应该在 A.h 中声明 class B,在 B.h 中声明 class A,再在各自的 cpp 实现文件中包含对方的头文件。


如果说类 A,B 属于不同的命名空间,就应该在声明的时候这样写:

namespace _A
{
    class A;
}

类 B 的声明也一样。


注意这种解决办法是针对两个类分别引用对方的指针的。如果说直接用了对方的对象,那么还会编译错误:使用未定义的类 A。


而且,这种情况下,头文件里面不能写实现!(给我长了个教训,我以后尽量不在头文件里面写实现了)

因为现在实现是写在 cpp 里面的,cpp 包含了对方的头文件,所以写实现没有问题。但是头文件里面还只是声明了一下而已,要是写了关于另一个类的实现,也会报错:使用未定义的类 A。


另一种情况,如果在 A 类中用了 B 类的对象而不是指针,就必须要在 A.h 中包含 B.h 了。但是 B.h 不可再去包含 A.h 了,否则又会陷入相互包含的泥潭。此时建议 B 就用 A 的指针吧,这样只要在头文件里面声明 A 就行了。


总结:

  1. 头文件不能相互包含

  2. 如果 A 类包含了 B 类的指针,那么只需要在 A.h 里声明 B 类,在实现中包含 B.h 即可(不要在头文件里面写实现!

  3. 如果 A 类包含了 B 类的对象,那么 A.h 就必须包含 B.h

  4. 头文件的包含尽量减少,如果要包含,可在实现文件里面包含,头文件里面写声明。否则包含多了的话,头文件之间就容易形成错综复杂的包含关系。


不足:

这回是引用对方的类,如果是调用函数,那就要把声明都抄一遍,十分麻烦。所以还是多用类吧。


参考:

https://blog.csdn.net/changbaolong/article/details/6916441

https://blog.csdn.net/wangbingqian_110/article/details/79473862 

https://blog.csdn.net/a812073479/article/details/38542515 





返回首页


Copyright (C) 2018-2024 huidong