c++中头文件互相包含的方法讲解
程序员文章站
2023-10-28 20:05:46
如果两个类想要相互使用对方,比如a想要有b的指针,而b被点击时要使用a的方法(例如窗口和按钮),想拥有a的指针,就会想到两者互相包含对方的头文件。(注意无论如何都不可能做到诸如a拥有b的实例,而b拥...
如果两个类想要相互使用对方,比如a想要有b的指针,而b被点击时要使用a的方法(例如窗口和按钮),想拥有a的指针,就会想到两者互相包含对方的头文件。(注意无论如何都不可能做到诸如a拥有b的实例,而b拥有a的实例,这样的话会出现内存的迭代使得两者占用内存无限大)
第一种方法(错误)
a.h
#pragma once #include "b.h" class a{ public: b* b; };
b.h
#pragma once #include "a.h" class b{ public: a* a; };
根据c++编译规则可知这样做是不可行的,因为在编译时假如首先编译a.h,发现它引用b.h,就导入b.h,b.h又包含a.h,如此迭代包含是无法做到编译的(可查看c++编译原理相关资料)
第二种方法(正解)
a.h
#pragma once #include "b.h" class a{ public: b* b; void methoda(); };
a.cpp
#include "a.h" void a::methoda() { b->methodb(); }
b.h
#pragma once class a; // 重点,没有包含a.h,只是声明a为一个类型,与之前声明的a没有关系 // 如果在此.h文件中使用a类型的任何属性方法都会报错 class b{ public: a* a;//使用的本文件声明的a类型 void methodb(); };
b.cpp
#include "b.h" #include "a.h" // 缺失这个包含会报错,此时才是给b.h中声明的a类定义 void b::methodb() { a->methoda(); }
解释
首先需要明确的是c++是以cpp文件为编译单元的,(也就是对每个cpp编译一次),当我们采取第二种方式时,当编译b.cpp这个编译单元是,实际上编译的是
// part1 // b.cpp先include "b.h",以下为b.h中的内容 class a; class b{ public: a* a; void methodb(); }; // part2 // b.cpp后include "a.h",以下为a.h中的内容 #include "b.h" // 已经导入就不再第二次导入 class a{ public: b* b; void methoda(); }; // part3 // b.cpp include后面的内容 void b::methodb() { a->methoda(); }
所以说是
1. part1(b.h)说明了a是一个类名称, 利用了a名称声明b类里面的a* a,
2. part2(b.cpp include a.h) 给出类a的定义(但没有给出方法定义)
3. part3定义b类methodb时使用a.h声明的methoda方法