C++如何解决头文件循环嵌套问题

C++如何解决头文件循环嵌套问题

一个项目中,有时我们会遇到这样的情况,两个类之间需要相互通讯,它们相互之间都要调用对方的函数。比如下面的例子中,有ParentChild两个类,它们都含有一个名为update的方法。Parent当中含有一个Child的实例,当Parentupdate执行时,Child实例的update也需要执行,并且Child实例执行update的过程中如果触发了某种条件会执行Parent中的某个函数foo。这样,两个类你中有我,我中有你,稍有不慎可能就写成了下面这种错误的形式:

//错误示范
//Parent.h
#pragma once

#include "Child.h"

class Parent
{
public:
	Parent();
	void update();
	void foo();

private:
	Child* mChild;
};

//Parent.cpp
#include "Parent.h"

Parent::Parent() : mChild(nullptr)
{
	mChild = new Child();
}

void Parent::foo()
{
	//do something
}

void Parent::update()
{
	mChild->update(this);
}

//Child.h
#pragma once

#include "Parent.h"

class Child
{
public:
	void update(Parent*);
};

//Child.cpp
#include "Child.h"

void Child::update(Parent* parent)
{
	//do something
    if (/*some condition triggered*/)
    {
        parent->foo();
    }
}

写成这种形式,代码的文本编辑器一般是不会认为它有问题的,从逻辑上考虑似乎也没有什么错。但是,编译的时候会报错,我们来考虑一下为什么。假设我们在main.cpp当中包含的是Parent.h头文件,那么在解析代码时,先将Parent.h中的内容展开;Parent.h的开头包含了Child.h,再将Child.hParent.h的开头展开;Child.h的开头虽然又包含了Parent.h,但是由于此时Parent.h已经被包含过一次,在#pragma once指令或者头文件宏的约束下会避免将Parent.h再次展开,最终呈现的样子大概是这样的:

class Child
{
public:
	void update(Parent*);
};

class Parent
{
public:
	Parent();
	void update();
	void foo();

private:
	Child* mChild;
};

很明显,当编译器自上而下编译时,碰到void update(Parent*)一句时,由于Parent的声明在后面,编译器找不到Parent的相关声明,所以会报错。

其实,解决的方法也很简单,就是把头文件的include指令改成一个预先的声明class XXX;,并将include指令放在cpp文件里,正确的代码如下:

//正确示范
//Parent.h
#pragma once

class Child; //这里发生了改变

class Parent
{
public:
	Parent();
	void update();
	void foo();

private:
	Child* mChild;
};

//Parent.cpp
#include "Parent.h"
#include "Child.h" //将头文件的include放在cpp文件里

Parent::Parent() : mChild(nullptr)
{
	mChild = new Child();
}

void Parent::foo()
{
	//do something
}

void Parent::update()
{
	mChild->update(this);
}

//Child.h
#pragma once

class Parent; //这里发生了改变

class Child
{
public:
	void update(Parent*);
};

//Child.cpp
#include "Child.h"
#include "Parent.h" //将头文件的include放在cpp文件里

void Child::update(Parent* parent)
{
	//do something
    if (/*some condition triggered*/)
    {
        parent->foo();
    }
}

为了避免这种头文件循环嵌套的问题出现,我们应当尽量避免在头文件中引入其他头文件,改成在对应的cpp文件中引入,如果头文件中引用了其他类的对象或者其指针,我们可以在头文件开头将对应类预先声明。但是,假如头文件中含有某个类具体的成员变量或者函数,就不能采用预先声明的方法了。

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值