如果两个类想要相互使用对方,比如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方法
如果不理解可以阅读 C/C++ 中头文件相互包含引发的问题