漫谈:C C++ 嵌套包含与前置声明

 初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


目录

嵌套包含导致无限

要有结束机制终止无限

头文件的避免重复包含机制

结构可以包含指针而不是嵌套

不可避免的成员互相调用

总结

结构不可能对象嵌套

但结构可以包含另一个结构的指针,只需要前置声明

操作结构成员代码无法通过前置声明解决,只能放到cpp文件里面去


嵌套包含导致无限

        C、C++的头文件和结构都是可以互相包含的,虽然头文件和数据结构是完全不相干的东西,但是嵌套包含这种事,是有其内在的规律的。

        两个“东西”的互相包含是不可能的,互相嵌套至少会产生一个“无限”:无限空间、无限时间或者无限精度。

        自包含就是递归,函数递归会产生无限层级,从而需要无限时间和无限尺寸的栈空间,结构的递归在编译器计算结构尺寸这一步就会遇上无限。

要有结束机制终止无限

        所以一定要某种机制破坏无限,对于递归函数我们都知道,必须要有结束条件,到了某一步停止递归。

        对结构的互相调用呢?我们似乎本能地觉得没什么啊,互相包含,水乳交融嘛,比如

--示意代码,不严格
struct A
{struct B b;int a;
}
struct B
{struct A a;int b;
}

        这不挺好吗?但是这个代码注定无法编译,因为结构A有多大?整数4字节,再加上B,B包含一个整数和一个A,就是4+4+A,A又是4+B,就是4+4+4+B,B又是4+A……子子孙孙无穷匮也。

        头文件也是如此,A.h包含B.h,B.h又包含a.h,编译器到这里也傻眼了,无限包含停不下来。

头文件的避免重复包含机制

        当然了,解决头文件的互相包含很简单,对头文件有结束包含的机制:

#ifndef XXXX_H
#define XXXX_H//头文件内容#endif

        或者更简单的:

#pragma once

        这是个编译器指令,大部分编译器都支持。

        头文件这么做很简单,数据结构包含怎么解决?数据结构的互相包含没法用头文件那种机制解决,压根不能那样做,因为得到的数据结构不是预期的。

结构可以包含指针而不是嵌套

        那么为什么还能看到很多数据结构互相包含呢?不互相包含为什么需要前置声明呢?

        嗯……你指的是这样的代码吗?

--代码示意,不严格struct B;--这是前置声明,仅仅说明B是一种结构的名字,具体内容不知道struct A
{B * b;--这是指针,任何指针都是同样的长度,跟指向的东西没关系int a;
};

        看清楚啊,里面只是用到了指针——指针的大小和指向的数据的类型无关。编译器知道B是个类型名就可以生成A了,只有在后续使用b->的时候编译器才需要知道B的具体结构。

不可避免的成员互相调用

        即使我们不犯两个结构互相包含这种错误,而且我们也知道用前置声明来解决指针问题,我们也仍然会遇到头文件问题:

//A.h
#include "B.h"
class A
{
public:int iA;void fA(B * b){b->iB;}
};//B.h
#include "A.h"
class B
{
public:int iB;void fB(A * a){a->iA;}
};

        由于两个类里面要用到->操作,编译器必须知道指针指向的结构的全部信息,所以必须包含头文件,这就不可避免地发生了头文件互相包含,当然我们在cpp文件里同时包含这两个头文件或仅仅只包含一个的时候,都会发生无限嵌套。

        不过前面已经说了头文件有避免无限嵌套的机制,而且一般每个头文件都应该使用这个机制。好吧,假设已经在上面的源码里添加了这个机制,那么处理A.h时发生什么:

  1. 处理A.h,记住A.h已经包含
  2. 包含B.h,记住B.h已经包含,此时B.h的内容被嵌入到A.h前面(替换包含语句)
  3. 处理B.h,又遇到包含A,发现A.h已经包含,所以不处理,无限嵌套被终止

        于是得到了如下代码:

//A.h//B.h//#include "A.h"--已经包含过,忽略class B{public:int iB;void fB(A * a){a->iA;}};
class A
{
public:int iA;void fA(B * b){b->iB;}
};

        编译器试图编译这个代码,却发现A未定义,即使在B.h加上A的前置声明也只能解决fB的参数“A* a”的问题,不能解决函数体里面的“a->iA”。

        这个问题唯一的解决方法就是把函数体放到cpp文件里面去。

总结

  • 结构不可能对象嵌套

  • 但结构可以包含另一个结构的指针,只需要前置声明

  • 操作结构成员代码无法通过前置声明解决,只能放到cpp文件里面去


(这里是结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/10537.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

盛邦安全拟战略收购卫星通信加密厂商天御云安

近日,远江盛邦(北京)网络安全科技股份有限公司(以下简称“盛邦安全”,股票代码:688651)对外公布,拟使用自有资金不超过人民币3000万元持有北京天御云安科技有限公司(以下简称“天御云安”&#…

electron 视频抓图并保存图片到本地

1. 思路: 1.1 通过canvas生成一块画布,在画布上绘制图形 let videoEl document.getElementById("testVideo");let params {videoEl,quality:0.95}let canvasEl document.createElement(canvas);canvasEl.width videoEl.width;canvasEl.he…

开启多线程下变量共享与私有问题

开启多线程下变量共享与私有问题 🌵ThreadLocal和Atomic是Java中用于多线程编程的两个重要工具。 ThreadLocal是一个线程局部变量,它为每个线程提供了独立的变量副本,确保每个线程都可以访问自己的变量副本而不会影响其他线程的变量。在多线…

json-server 模拟接口服务

前端开发经常需要模拟接口请求,可以通过 json-server 实现。 1. 安装 json-server 在前端项目的终端命令行中执行 npm i json-server2. 创建数据源 在项目中新建文件 db.json ,与 package.json 同级,内容为模拟的数据 注意 json 文件对格式…

选择步入式高低温试验室价格除外还需要考虑哪些方面?

选择步入式高低温试验室时,价格是一个非常重要的考虑因素。但是,步入式高低温试验室价格不仅仅是主要决定因素,我们还需要考虑到设备的性能、质量、可靠性以及售后服务等多方面因素。接下来给大家具体介绍的关于选择步入式高低温试验室价格除…

conan2 基础入门(06)-conanfile.py入门

conan2 基础入门(06)-conanfile.py入门 文章目录 conan2 基础入门(06)-conanfile.py入门⭐准备预备文件和Code ⭐使用流程指令 ⭐具体讲解conanfile.pyconan install END视频教学 ⭐准备 注意,如果想跟好的学习conanfile.py建议使用python来安装conan。 当然使用其…

shell 脚本curl的时候,变量未被正确替换

有问题的脚本: updateRes\$(curl --location --request PUT http://172.16.80.88:3100/api/application/devopsBuildVersion \--header Authorization: bGFtcF93ZWJfcHJvOmxhbXBfd2ViX3Byb19zZWNyZXQ \--header Content-Type: application/json;charsetUTF-8 \--…

C++入门系列-构造函数

🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会…

Day 28 MySQL的数据备份与恢复

数据备份及恢复 1.概述 ​ 所有备份数据都应放在非数据库本地,而且建议有多份副本 备份: 能够防止由于机械故障以及人为误操作带来的数据丢失,例如将数据库文件保存在了其它地方 冗余: 数据有多份冗余,但不等备份&…

利用PyTorch实现概率建模和贝叶斯推断

1.PyTorch概率建模和贝叶斯推断 在 PyTorch 上进行概率建模和贝叶斯推断通常涉及以下几个关键步骤: 定义概率模型:首先,你需要定义一个概率模型,该模型描述了数据生成的过程。在 PyTorch 中,这通常涉及到定义模型的参数…

JVM---垃圾回收

目录 一、C/C的内存管理 二、Java的内存管理 三、垃圾回收的对比 四、Java的内存管理和自动垃圾回收 五、方法区的回收 手动触发回收 六、堆回收 如何判断堆上的对象可以回收? 引用计数法 可达性分析算法 五种对象引用 软引用 软引用的使用场景-缓存 弱引用 虚…

推荐算法详解

文章目录 推荐算法引言基于内容的推荐原理算法步骤注意点可以优化的地方示例代码讲解 协同过滤推荐原理算法步骤注意点可以优化的地方示例代码讲解 混合推荐系统原理算法步骤注意点可以优化的地方示例1代码讲解1示例2代码讲解2 基于知识的推荐原理算法步骤注意点可以优化的地方…

机柜风扇KTS011温湿度控制器KTO011风机控制温控器机械开关温控仪

品牌:威驰 型号:KTS011常开 产地:中国大陆 颜色分类:KTS011常开,KTO011常闭 KTS011与KTO011的区别 KTS011,常开型,可搭配风扇/风机使用:当环境温度超过温控器设定温度,温控…

数据结构与算法===贪心算法

文章目录 定义适用场景柠檬水找零3.代码 小结 定义 还是先看下定义吧,如下: 贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是全局最好或最优的算法。 适用场景 由于…

在线教育系统怎么留住用户,什么叫k12在线教育机构?它的价值是什么?

k12在线教育机构,近年来时常被人提起,当然,也有很多人对此不太熟悉,大众的印象仍然停留在传统教育的阶段,所以,什么叫k12在线?其实,弄的不太明白,所以,也来给各位科普下…

Kafka的安装及接入SpringBoot

环境:windows、jdk1.8、springboot2 Apache KafkaApache Kafka: A Distributed Streaming Platform.https://kafka.apache.org/ 1.概述 Kafka 是一种高性能、分布式的消息队列系统,最初由 LinkedIn 公司开发,并于2011年成为 Apache 顶级项目…

C语言-课程管理系统-大作业

C语言编写课程管理系统 1 需求分析2 需要查的知识点3 数据结构和基础函数功能3.1 课程数据结构3.2 菜单和选择项3.3 从文件中加载课程信息到内存3.4 将内存中的课程信息保存到文件3.5 将输入的字符串格式化为课程信息结构体 4 主要功能函数4.1 录入课程信息函数4.2 浏览课程信息…

2024全新小狐狸AI免授权源码

源码安装说明: 下 载 地 址 : runruncode.com/php/19757.html 1. 在宝塔新建一个站点,选择 PHP 版本为 7.2、7.3 或 7.4。将压缩包上传到站点的根目录,并设置运行目录为 /public。 2. 导入数据库文件,该文件位于 …

gap意识

在学习的过程中,遇到一个知识点搞不懂,或是在工作的过程中,遇到一个难题解决不了,很多时候不是我们的能力不行或是智商不够,而是我们当前的认知与那个知识点或难题之间存在较大的 gap。比如,若没学过线性代…

最大9W升压型DCDC多串LED恒流驱动

描述 AP9234是一款由基准电压源、振荡电路、误差放大电路、相位补偿电路、电流限制电路等构成的CMOS升压型DC/DC LED驱动。由于内置了低导通电阻的增强型N沟道功率 MOSFET,因此适用于需要高效率、高输出电流的应用电路。另外,可通过在VSENSE端子连接电…