【C/C++】解决“两个类的头文件相互引用/超前引用”问题的方法

2023-05-16

一、什么是超前引用?

所谓 超前引用 是指一个类型在定义之前就被用来定义变量和声明函数。一般情况下C/C++要求所有的类型必须在使用前被定义,但是会存在一些特殊情况导致这种要求无法满足,例如

//类A的头文件
#ifndef _A_H_
#define _A_H_
#include "B.h"
class A
{
public:
    int x;
    B b;
}
#enif

//类B的头文件
#ifndef _B_H_
#define _B_H_
#include "A.h"
class B
{
public:
    int y;
    A a;
}
#enif
  • 当一个类 A 中包含另一个类 B 的对象时,则必须在A的源码文件中声明另一个类的头文件;那么如果两个类都互用到了对方的对象,理论上就要互相包含头文件。
  • 如下代码所示,但是这样是无法通过编译的,其原因是它们的头文件互相包含了,你包含我、我又包含你、没完没了!思考一下是不是会出现 a.b.a.b.a.b.a.b.a.b…无穷尽的情况,这种定义方式类同程序中的死循环。
  • 从编译器角度看,编译 A.CPP 时,系统首先定义宏 _A_H_,然后包含 B.h,而 B.h 中的 #include "A.h" 由于 _A_H_ 已经定义,所以不再起作用。在类的声明中,A a 就会让编译器产生 "A" 类型没有定义之类的错误,编译 B.CPP 文件出现的错误可以类似得到。  

二、怎么解决超前引用?

超前引用导致的错误根据不同情况一般有以下几种处理办法:

1、使用类的前置声明

对于所有代码在同一个文件中的情况,在超前引用一个类之前,首先用前置声明说明该标识符是一个类名,即将被超前引用。其使用方法是:

  • a)  用class B;声明即将超前引用的类名
  • b)  定义class ClassA
  • c)  定义class ClassB
  • d)  编写两个类的实现代码。

而一般情况下,Class A和Class B分别有自己的头文件和cpp文件,这种方法需要演变成如下所示,需要注意的是这种方法切记不可使用类名来定义变量和函数的变量参数,只可用来定义引用或者指针。

  • a) 分别定义Class A和Class B,并在cpp文件中实现之
  • b) 在两个头文件的开头分别用class B;和class A;前置声明来声明对方
  • c) 在两个cpp文件中分别包含另外一个类的头文件
//文件A.h中的代码  
//#include "B.h",放到A.cpp中去  
class B;  
  
class A  
{  
public:  
    B* b;  
};  
  
//文件B.h中的代码  
//#include "A.h",放到B.cpp中去  
class A;  
  
class B  
{  
public:  
    A* a;  
};

2、使用全局变量

全局变量可以避免超前引用,将类对象的extern语句加在该类头文件的最后。

3、使用基类指针

这种方法是在必须使用超前引用类的地方一律用基类指针。而一般情况下,两个互相引用的类并不涉及其基类,因此不会造成超前引用。以开始的例子说:在A类中用 Bfather* 代替 B*,或者在B类中用 Afather* 代替 A* 以此来避免出现相互的超前引用。

三、如何避免超前引用

其实上述三种方法并不一定能解决全部的超前引用问题,自己在最近的代码中就遇到了上述三种方法都解决不了的互相引用的问题,最后的解决方法是想办法将A中对于B的引用给去除,根本解决方法还是要尽可能避免超前引用。

那么对于超前引用需要注意哪些问题呢?

  • 不要乱包含头文件,在不需要包含头文件的情况下尽量不要包含。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象或者访问到类的具体成员,那么前置声明就可以解决问题。
  • 对于非库函数头文件,尽量在CPP文件中包含,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并编译成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C/C++】解决“两个类的头文件相互引用/超前引用”问题的方法 的相关文章

  • Python GUI开发之Tkinter:详解安装和使用方法

    Python GUI开发之Tkinter 详解安装和使用方法 Tkinter是Python中最常用的GUI图形库之一 它是Python自带的标准库 所以不需要额外安装 在Python的标准库中 Tkinter模块被用来创建桌面GUI应用程序
  • windows下ssh免密登录ubuntu

    一 先查看要登录的服务器是否安装ssh server服务 dpkg l grep ssh 若没有则需要安装 apt span class token operator span get install openssh span class
  • CentOS 7下安装MPICH3.2过程详解

    最近由于专业需要 xff0c 需要在CentOS 7平台下安装并行计算包MPICH 由于我才接触Linux xff0c 鸟哥的基础入门书也才看了四分之一不到 xff0c 所以安装也一步一步按照官方给的文档安装 官方安装方法 首先附上官网给出
  • 洛谷 P3366 【模板】最小生成树

    洛谷 P3366 模板 最小生成树 题目 给出一个无向图 xff0c 求出最小生成树 xff0c 如果该图不连通 xff0c 则输出orz 题目链接 模板 最小生成树 洛谷 输入 第一行包含两个整数N M xff0c 表示该图共有N个结点和
  • 2019 计蒜之道 复赛 D “星云系统”

    2019 计蒜之道 复赛 D 星云系统 题目 现在给定你一个字符串s以及一个整数k xff0c 请求出s的字典序最小的长度为k的子序列 题目链接https nanti jisuanke com t 39614 输入格式 第一行一个由小写英文
  • Linux mysql 配置

    一 数据库处室化密码 刚刚装好的数据库需要重置密码 alter user user identified by 39 12345678 39 如果是测试环境 或者自己玩的环境 设置密码过于简单 可以通过一下命令修改关于密码的校验 set g
  • 二进制安装Kubernetes(k8s) v1.26.0 IPv4/IPv6双栈

    二进制安装Kubernetes xff08 k8s xff09 v1 26 0 IPv4 IPv6双栈 https github com cby chen Kubernetes 开源不易 xff0c 帮忙点个star xff0c 谢谢了 介
  • ThinkPad E430 蓝牙驱动 BCM43142A0

    最近我意外发现公司的 ThinkPad E430 笔记本竟然是带有蓝牙的 D 查看蓝牙设备标识 ID 利用 lsusb 命令找到蓝牙模块信息 Bus 001 Device 004 ID 105b e065 Foxconn Internati
  • cephadm 安装部署 ceph 集群

    介绍 手册 xff1a https access redhat com documentation zh cn red hat ceph storage 5 html architecture guide index http docs c
  • PVE Cloud-INIT 模板配置

    PVE Cloud INIT 模板配置 Cloud init是什么 Cloud init是开源的云初始化程序 xff0c 能够对新创建弹性云服务器中指定的自定义信息 xff08 主机名 密钥和用户数据等 xff09 进行初始化配置 通过Cl
  • openstack 环境部署

    22 1 了解云计算 人类基于千年的物种衍变基础 xff0c 在这个世纪终于有了爆发式的科技成果 xff0c 尤其这二十年内互联网的发展 xff0c 更像是一种催化剂 xff0c 让原本已经热闹的地球更加的沸腾 xff0c 互联网经济泡沫破
  • C语言,计算圆的面积程序

    C语言 xff0c 计算圆的面积程序 span class token comment 计算圆的面积程序 日期 xff1a 2020 8 29 姓名 xff1a 张倩峰 span span class token macro propert
  • 博图软件搜索不到网卡

  • 台达伺服手动调试

  • 博途V15.1激活工具出错。

    博图V15 1激活 xff0c 软件出错 出现以下报错信息 解决方法 xff1a 下载新版本激活工具 再次激活
  • winCC正常运行,不显示画面。

    winCC正常运行 xff0c 不显示画面 解决方法 xff1a 需要重装系统 xff0c 重新安装博途
  • S7-1500PLC仿真

    S7 1500PLC仿真
  • 一些已安装产品需要许可证,请启动Automation License Manager

    更新系统版本号 完成更新 xff0c 再次安装即可解决该问题
  • ubuntu 硬盘管理工具

    就我目前所用的系统举例说明吧 xff0c 应该都大同小异的 有图形界面的 xff0c 也有命令行的 xff1a 首先是 ubuntu 系统自带的 Disk Utility 工具集 利用该工具可以对硬盘进行 Format Drive View

随机推荐

  • MCS-51单片机,定时1分钟,汇编程序

    MCS 51单片机 xff0c 定时1分钟 xff0c 汇编程序 去博客设置页面 xff0c 选择一款你喜欢的代码片高亮样式 xff0c 下面展示同样高亮的 代码片 span class token constant ORG span 00
  • c++枚举字符串转换工具

    为什么会需要这样一个枚举转字符串 xff0c 字符串转枚举的工具 xff1f 在太多的工程中 xff0c 我们可能都需要将一些枚举 整形标记打到日志中去 xff0c 如果只打印数组 xff0c 那也不行啊 xff0c 出问题翻看日志 xff
  • AD16在PCB布局的时候如何批量复制布局布线!!

    本人也是看了很多博主的帖子反反复复推敲 xff0c 最后发现有的博主没讲到关键部分所以在批量复制布局的时候总是事与愿违 话不多说请看招 xff01 第一步选中需要复制的布局 xff01 如图所示 第二步 复制选中布局的 offset Cha
  • Atcoder abc250 题解 (A~G)

    A Adjacent Squares xff08 枚举 xff09 枚举一下 xff0c 满足题意则ans 43 43 即可 cin span class token operator gt gt span h span class tok
  • 简单理解epoll

    epoll系列系统调用 epoll是Linux特有的I O复用函数 epoll使用一组函数来完成任务 epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中 epoll需要使用一个额外的文件描述符 xff0c 来唯一标识内核中的事
  • glibc-2.23 puts源码分析

    在分析puts代码之前先看一些基本的知识 一些flag span class token macro property span class token directive hash span span class token direct
  • Sublime Text 搭建 C++ 环境

    一 下载MinGW文件 1 下载mingw get setup xff1a 网址 xff1a https sourceforge net projects mingw 由于这是境外网站 xff0c 请自行解决连接问题 xff08 下载的文件
  • PlayFair加密方法原理及C+ +实现

    普莱费尔密码 xff08 英文 xff1a Playfair cipher 或 Playfair square xff09 是一种使用一个关键词方格来加密字符对的加密法 xff0c 1854年由一位名叫查尔斯 惠斯通 xff08 Charl
  • Python爬虫进阶(三):Selenium模拟浏览器操作

    目录 关于Selenium 启动webdriver selenium查找元素 selenium模拟用户行为 执行JS 模拟滚动条滚动 模拟鼠标操作 模拟键盘操作 其他常用函数 这一节我们来讲解使用selenium来模拟浏览器操作进而方便快捷
  • Python爬虫进阶(十):实战,Scrapy爬取贴吧

    目录 前言 目标 使用scrapy shell测试目标 1 为什么 2 尝试直接进入tieba baidu com 3 准备header 3 测试爬取目标 编写item 编写pipeline 编写spider 1 编写start reque
  • 关于WM_PAINT,窗口重绘invalidate、onidle

    一 WM PAINT 系统会在多个不同的时机发送WM PAINT消息 xff1a 当第一次创建一个窗口时 xff0c 当改变窗口的大小时 xff0c 当把窗口从另一个窗口背后移出时 xff0c 当最大化或最小化窗口时 xff0c 等等 xf
  • RMXP脚本解析(十五):Game_Battler(分割定义三)

    目录 前言 Game Battler xff08 分割定义三 xff09 代码解析 第一命中与第二命中 计算公式 xff08 真 xff09 effective xff08 攻击有效标志 xff09 的生效条件 属性修正 对象是Game A
  • RMXP脚本解析(#三十一):RGSS与RMXP数据库(十一.MoveRoute)

    前言 本类目前看到的实例出现在Game Character中 xff0c 作为其类变量 64 move route存在 本类用于描述移动的路径 RPG MoveRoute module RPG class MoveRoute def ini
  • 关于笔者个人博客访问与攻击的一个小统计,最常被利用的居然不是PHP框架?

    目录 前言 测试时间 测试用脚本 测试结果 xff08 ip部分 xff09 测试结果 xff08 url部分 xff09 前言 我只是闲的没事 xff0c 但是这一统计下来确实发现了一些有意思的事情 我的个人博客 xff08 August
  • 追忆童年系列:记一次寻找Flash小游戏的经历

    目录 Chapter 前言 Chapter 寻找游戏源文件 Chapter 寻找游戏源 Chapter 第二个版本的游戏 Chapter 解包及抓包 Chapter 游戏剧情 Chapter 最新 xff0c 最新的进展 Chapter 前
  • 进阶Django(三):模型外键、多对多关系、自关联外键及Meta类

    目录 前言 模型中的映射关系 1 物理外键与逻辑外键 2 Django中的外键 xff08 一对一 一对多关系 xff09 3 Django中的多对多关系 3 1 使用ManyToManyField自动建立多对多关系 3 2 另一种建立多对
  • Unity游戏教程初步(八):Animator的使用

    1 前言 本节中我们来介绍Unity的动画系统以及管理动画剪辑 xff08 Animation Clip xff09 的组件Animator 2 Unity中的动画系统 Unity的动画系统又称为Mecanim xff0c 是一个基于动画剪
  • 手机模拟器安装证书抓包

    目录 1 抓包软件 2 抓取HTTPS包 3 不同抓包软件配置步骤 4 代理 1 抓包软件 由于是手机模拟器 xff0c 所以可以使用adb进入命令行 xff0c 方便一些 抓包软件手机上的有HTTPCanary xff0c 电脑上需要配置
  • JAVA BP插件开发(一):基础插件开发

    本文会包括BP插件开发流程及打包 xff0c API xff0c javaswing xff08 UI xff09 部分的内容 阅读完本文后 xff0c 读者将初步具有开发BP插件的能力 1 开始开发 我们使用IDEA作为开发工具 xff0
  • 【C/C++】解决“两个类的头文件相互引用/超前引用”问题的方法

    一 什么是超前引用 xff1f 所谓 超前引用 是指一个类型在定义之前就被用来定义变量和声明函数 一般情况下C C 43 43 要求所有的类型必须在使用前被定义 xff0c 但是会存在一些特殊情况导致这种要求无法满足 xff0c 例如 类A