欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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方法