类定义与前置声明

C++编程法则365天一天一条(220)类的前置声明 在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提示。 代码一: // ForwardDeclaration.h #include <iostream> using namespace std; class B; // 这是前置声 阅读详情
本文要写的是近期做项目过程中遇到的一个语法方面的小问题,下文从问题描述,解决思路以及总结这样的三段式描述来记录一下,以为备忘。

        问题描述很简单。在实现一个模块的过程中,在头文件x.h中定义了class B, class B继承自class A; class A定义在y.h中;为了避免两个头文件之间不同数据结构定义之间的复杂依赖导致的问题,在头文件x.h中使用了对class A的前置声明,在源文件x.cxx中包含了头文件x.h和y.h。

x.cxx:

#include "x.h"
#include "y.h"
use class B;

x.h:

#ifndef X_H_INCLUDED
#define X_H_INCLUDED
class A;
class B:public A{
  ...
};
#endif

y.h:

#ifndef Y_H_INCLUDED
#define Y_H_INCLUDED
class A{
   ...
};
#endif

编译报错:

x.h:error: invalid use of undefined type struct A
x.h:error: forward declaration of struct A  


解决思路:

我试图简单地调换了一下两个头文件在x.cxx中的包含顺序,编译通过。那么这里的问题在哪儿呢?看看将x.h和y.h分别在x.cxx中手动预处理之后会发生什么样的剧情。有两种情形:

1)如果x.h在y.h之前包含,我们得到与处理后的x.cxx的简要描述如下:

class A;
class B:public A{};
class A{};
use class B;

2)如果y.h在x.h之前包含,我们得到预处理后的x.cxx的简要描述如下:

class A{};
class A;
class B:public A{};
use class B;

不难看到,编译报错的原因在于派生类class B在定义之前编译器没有看到基类class A的定义,由于没有基类的定义,就无法为派生类分配对象。这就是两个头文件不同的包含顺序会导致正确和错误两种编译结果的本质原因。


总结:

        从技术层面上,在大型软件中,模块化编程是常用的方式,特别在OO程序中,跨头文件的派生类的定义是比较多的;与此同时,就像我在之前的博文中提到的,在头文件中使用前置声明是一个很好的编程习惯。两者结合的时候,我们需要特别注意源文件中的头文件包含顺序,避免出现在定义派生类时没有基类定义的错误。

        从解决问题的方法学方面,我的感觉是,解决问题的过程就是一个先将问题进行简化和抽象,然后再抽丝剥茧分析问题、按图索骥找到解决方案的过程,牢牢掌握已知的线索,逐渐还原问题的本质。简单问题如此,复杂问题更是如此。





手把手教你用西门子博图V18配置阿特拉斯PF6000拧紧枪PN通讯(附完整GSD文件与ToolsTalk配置文件) 本文详细介绍了如何使用西门子博图V18配置阿特拉斯PF6000拧紧枪的PN通讯,包括硬件连接、网络参数规划、ToolsTalk软件配置及博图工程设置。通过完整的GSD文件和配置文件,帮助工程师快速实现高精度拧紧设备与PLC的高效通讯,适用于汽车装配和电子制造等工业自动化场景。 阅读详情

相关推荐

基于smart_rtmp直播,最简单的部署手册

版本号 添加内容 修改时间 V1.0 新建 2021年12月30日 V1.1 增加网页播放 2021年12月31日 V1.2 增加是否可以多流和测试数据 2022年1月5日 目录 一、软件储备 1.推流软件:OBS 2.服务器流媒体软件:smart_rtmp 3.播放软件:Pot...

qq_28768477的博客 1万+

头文件包含顺序

头文件包含顺序 原理:当通过#include指令包含另一个头文件时,编译预处理器用头文件的内容取代#include指令,也就是说,头文件的所有内容最终都会被合并到某一个或某几个源文件中,如此将每一个包含的头文件递归的展开后形成的源文件就叫编译单元。 所以: 实际上是只编译源文件 源文件中在包含头文件的地方,将被包含头文件中的代码全部拷贝进去进行编译; 包含头文件是有顺序的,因为包含头文件的顺序意味着该头文件在源文件进行展开的顺序。 推荐顺序: C标准库、C++标准库、其它库的头文件、你自己工程的头文件。

qq_40604571的博客 1537

QT应用编程: Win10系统下QT5.12搭建Android开发环境(配件齐全)

在win10系统下,搭建QT5.12.6 的Android开发环境。

7690

多个第3方库 头文件包含顺序

也就是说,如果库 B 依赖于库 A,则应先包含库 A 的头文件,再包含库 B 的头文件。这是因为,如果库 A 的头文件中定义了库 B 所需的类型或函数,而您在包含库 B 的头文件之前已经定义了这些类型或函数,则会出现编译错误。在包含头文件时,应仔细检查每个头文件中定义的类型、函数和宏,并确保包含的顺序正确无误。在包含多个第三方库的头文件时,头文件包含的顺序可能会影响编译的结果,特别是当这些库有一些共同的依赖时。最后包含本地头文件,例如您自己编写的头文件或本地项目的头文件。先包含系统头文件,例如。

323

PX4从放弃到精通(二十二):日志

文章目录前言一、下载日志二、ulog转CSV三、利用flightplot软件分析PX4的ulog日志1 windos安装2 ubuntu18.04安装四、使用PlotJuggler分析PX4日志五、设置日志记录条件六、添加自定义日志消息 前言 PX4 1.10以上固件 QGC 一、下载日志 将飞控链接地面站,在下图页面点击“刷新”,即可看到保存的日志(前提是要有TF卡) 选择需要下载的日志,点击右侧的“下载”,然后选择目录即可进行下载,如果想擦除所有的日志,可以点击右侧的“擦除全部” 二、ulog转CS

超维空间科技的博客 6796

SPMI总线协议(一)

系统电源管理接口( System Power Management Interface简称SPMI)是一种双线串行接口,用于连接片上系统(SoC)处理器系统的集成电源控制器(PC)与一个或多个电源管理集成电路(PMIC)电压调节系统。SPMI 使系统能够使用单个 SPMI 总线动态调整 SoC 内部电压域的电源和衬底偏置电压。移动设备和其他便携式设计正日益采用系SPMI)协议,实现多主多从系统,根据实时系统需求监测和动态控制供电电压。设计人员可以在系统级实现更低的功率。

qflook的博客 887

头文件的顺序问题

参照此文此文,我们 在建立动态的时候,在.h文件中添加的了一个类的头文件,如 #include “mylib.h” 头文件中定义了一个结构体;struct STU 在.cpp文件中,我们定义了函数 #include "mylib.h" #include <iostream.h> struct STU foo() { } 发现,当,将头文件#include "mylib.h"放在上面的位置,编译会报错,但是放在函数上边编译则没有问题,原因待查??? #include <.

modi000的博客 841

STM32(HAL库)驱动HC-SR04测距模块

本文介绍通过STM32F103C8T6单片机对HC-SR04测距模块进行驱动,并且通过串口对数据进行打印。

weixin_44597885的博客 2204

头文件包含顺序不当引起错误

昨天在写bug (不是)代码时,在编译的时候出现了“非法标记”与“语法错误”的报错,而且报错位置是一个不知道在哪个角落的文件。 这种其他文件里的错误总是出现的莫名其妙,而且又是编译错误,调试也没法调试,看的脑壳疼。 我起初以为是代码里的问题,于是注释掉全部的代码,一个个函数解除注释,来测试能否通过编译。但发现即使全部注释了也还是报错,于是我怀疑是头文件这里的问题。 参照了一下组内其他人的文件,发现他们的头文件包含顺序都是先包含自定义头文件,然后再包含标准库和第三方库文件。但我最后才包含了自定义头文件。于

weixin_42469326的博客 1325

Realtek千兆PHY RTL8211FS相关寄存器操作详解

通过合理配置和控制RTL8211FS寄存器,您可以实现对以太网的各种功能和参数的控制和配置。请注意,具体的寄存器操作和配置值可能因具体需求而有所不同,您应参考RTL8211FS芯片的数据手册以获取准确的寄存器说明和操作规范。我们将提供相应的源代码示例,以帮助您理解和实施这些操作。通过操作这些寄存器,我们可以配置和控制RTL8211FS芯片的各种功能和参数。需要注意的是,具体的寄存器操作和配置值会根据您的具体需求而有所不同。您需要参考RTL8211FS芯片的数据手册以获取详细的寄存器说明和操作规范。

RlDart的博客 2660

Android插件化和组件化面试题及参考答案

如何使用 Gradle 来管理 Android 项目中的模块依赖? Gradle 是一个强大的构建工具,在 Android 项目中管理模块依赖主要通过以下方式。 首先,在项目的根目录下的 build.gradle 文件中,需要配置仓库。一般会添加如 Google 的 Maven 仓库和 JCenter 等,例如在 repositories 部分添加: repositories { google() jcenter() } 对于模块依赖,在每个模块(例如 app

大模型大数据攻城狮的专栏 1185

关于头文件顺序的问题

今天在编写linear工具时出现了一个错误 #include <stdio.h> #include <malloc.h> #include "linear.h" #include "mec.h" #include "userType.h" 自己明明别写好了userTpye.h的头文件,为什么会频频报错,USER_TYPE类型没有定义。 询问了老师,查阅了一些资料后,发现这和头文件的顺序有关。 当我将头文件的顺序变为 #include <stdio.h>//系统头文件

weixin_45483328的博客 1114

华为OD机试 新系统真题 【数字系统转换器】

华为OD机试 新系统真题【数字系统转换器】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为OD机试真题【数字系统转换器】多语言题解。

qq_45776114的博客 542

C++里类的前置声明分析

我们先了解下C++下函数的情况,然后再类比到C++类 C++下函数声明和定义 我们在用C++写代码时(假设源文件只有一个main.cpp),经常会按照以下步骤写: 先对自定义的函数进行声明 在main函数里调用第1步里声明好的函数 编写函数的实际代码,这一步也叫函数的定义 可以看到C++允许函数的声明和定义分开,并且只要函数声明后就可以拿来使用,暂时不用去实现其具体定义,这其实也是可以对C/C...

爱就是是恒久忍耐的专栏 1万+

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

c++ using 前置声明_C++ 类声明 类前置声明范例

转载自http://www.cnblogs.com/staring-hxs/p/3244251.html在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提...

weixin_31201737的博客 258

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

关于C++中的前置声明

编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提示。 代码一: // ForwardDeclaration.h #include

sql112113的专栏 612

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

c++中类的定义与头文件的关系

class Stack;此句只是作为Stack class的前置申明,只是将calss名次告诉编译器,并未提供此class的任何其他信息。前置申明使得我们可以进行类指针的定义,或以此class作为数据型别://以下这种写法,必须先有class的前置申明才行Stack *pt=0;void process (const Stack&);接下来,在定义实际的Stack class object...

weixin_30535913的博客 143

#include和前置声明

#include和前置声明1. 当不需要调用类的实现时,包括构造函数,拷贝构造函数,赋值操作,成员变量,甚至是 地址操作时,就不用#include,只要前置声明就可以了。2. 当要用到类的上面那些“方法”时,就要#include。详细请阅读原文:http://blog.youkuaiyun.com/rogeryi/archive/2006/12/12/1439597.asp

jimmy54的专栏 227

c++ using 前置声明_详解C++ 前置声明

前置声明是C/C++开发中比较常用的技巧,主要用在三种情形:变量/常量,例如extern int var1;;函数,例如void foo();,注意类的成员函数无法单独做前置声明;类,例如class Foo;,也可以前置声明模板类:template classFoo;。如果类包含在名字空间中,需在名字空间内做前置声明:namespace tlanyan {class Foo;};,而不能这样:cl...

weixin_33997127的博客 363

c++中namespace和前置声明

前置声明一般用于要在一个类中使用另一个类,而另一个类的声明在后面或者其他文件中时 如类A和B class A{ private:       B *b; }; class B{ };这里类B在类A后面,但是类A中创建类B的指针了,所以要在类A前声明类B,将上面改成 class B; class A{ private:       B *b; }; clas

hhm853610070的博客 4594

C++知识分享:前置声明及其解析

前置声明是C/C++开发中比较常用的技巧,主要用在三种情形: 变量/常量,例如externintvar1;; 函数,例如voidfoo();,注意类的成员函数无法单独做前置声明; 类,例如classFoo;,也可以前置声明模板类:templateclass<typenameT1,intSIZE>Foo;。如果类包含在名字空间中,需在名字空间内做前置声明:namespacetlanyan{classFoo;};,而不能这样:classtlanyan::Foo;。 ...

致力于C语言C++知识分享! 1066

C++类的前置声明

转自:https://www.cnblogs.com/King-Gentleman/p/5081159.html   一、类嵌套的疑问 C++头文件重复包含实在是一个令人头痛的问题,假设我们有两个类A和B,分别定义在各自的头文件A.h和B.h中,但是在A中要用到B,B中也要用到A,但是这样的写法当然是错误的:  class B; class A{       public:     ...

RosyCloudsLee的博客 905

C++类前置声明和包含头文件的区别

转载自:C语言类前置声明和包含头文件的区别_Hesy_H的博客-优快云博客_c 前置声明 看完《Effective C++》条款31有感。。 尽量用前置声明代替头文件 假设有一个Date类 Date.h class Date { private: int year, month, day; }; 如果有个Task类的定义要用到Date类,有两种写法 其一 Task1.h class Date; class Task1 { public: Date getData(); }; 其二

csdndenglu的专栏 629

正确使用#include和前置声明(forward declaration)

差不多一年时间没用过C++写过程序了,由于工作的需要,我又回到了C++的阵形。在工作的过程中遇到了很多麻烦,当我往工程里加一个类,而且那个类又与工程里的类相关,如有那个类型的成员变量。情况如下 //////A.h/////////// class A { ....... }; ////////B.h////////// class B:A {

起点 1168
上一篇: 亚锦赛吐槽
下一篇: Windows 7系统应用软件故障修复备忘
IEEE2007
博客等级 码龄20年 4粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值