`
ladymaidu
  • 浏览: 678440 次
文章分类
社区版块
存档分类
最新评论

对类前置声明和包含头文件的一点理解

 
阅读更多

作者:朱金灿

http://blog.csdn.net/clever101

类的前置声明(forward declaration)和包含头文件(#include)的区别常常会迷惑我们,特别是涉及两个类相互包含的时候。因此我们有必要搞清楚二者的区别以及二者的适用场合。

首先我们需要问一个问题是:为什么两个类不能互相包含头文件?所谓互相包含头文件,我举一个例子:我实现了两个类:图层类CLayer和符号类CSymbol,它们的大致关系是图层里包含有符号,符号里定义一个相关图层指针,具体请参考如下代码(注:以下代码仅供说明问题,不作为类设计参考,所以不适宜以此讨论类的设计,编译环境为Microsoft Visual C++ 2005,Windows XP + sp2,以下同):

现在开始编译,编译出错,出错信息如下:

1>正在编译...

1>TestUnix.cpp

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C2143: 语法错误: 缺少“;(在“*”的前面)

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

1>Layer.cpp

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C2143: 语法错误: 缺少“;(在“*”的前面)

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

1>f:/mytest/mytest/src/testunix/symbol.h(14) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

1>Symbol.cpp

1>f:/mytest/mytest/src/testunix/layer.h(18) : error C2143: 语法错误: 缺少“;(在“*”的前面)

1>f:/mytest/mytest/src/testunix/layer.h(18) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

1>f:/mytest/mytest/src/testunix/layer.h(18) : error C4430: 缺少类型说明符- 假定为int。注意: C++ 不支持默认int

现在让我们分析一下编译出错信息(我发现分析编译信息对加深程序的编译过程的理解非常有好处)。首先我们明确:编译器在编译文件时,遇到#include "x.h"时,就打开x.h文件进行编译,这相当于把x.h文件的内容放在#include "x.h"处。编译信息告诉我们:它是先编译TestUnix.cpp文件的,那么接着它应该编译stdafx.h接着是Layer.h如果编译Layer.h那么会编译Symbol.h但是编译Symbol.h又应该编译Layer.h啊,这岂不是陷入一个死循环? 呵呵,如果没有预编译指令,是会这样的,实际上在编译Symbol.h再去编译Layer.hLayer.h头上的那个#pragma once就会告诉编译器:老兄,这个你已经编译过了,就不要再浪费力气编译了!那么编译器得到这个信息就会不再编译Layer.h而转回到编译Symbol.h的余下内容。当编译到CLayer *m_pRelLayer;这一行编译器就会迷惑了:CLayer是什么东西呢?我怎么没见过呢?那么它就得给出一条出错信息,告诉你CLayer没经定义就用了呢?TestUnix.cpp#include "Layer.h"这句算是宣告编译结束(呵呵,简单一句弯弯绕绕不断),下面轮到#include "Symbol.h",由于预编译指令的阻挡,Symbol.h实际上没有得到编译,接着再去编译TestUnix.cpp的余下内容。

当然上面仅仅是我的一些推论,还没得到完全证实,不过我们可以稍微测试一下,假如在TestUnix.cpp#include "Layer.h"#include "Symbol.h"互换一下位置,那么会不会先提示CSymbol类没有定义呢?实际上是这样的。当然这个也不能完全证实我的推论。

照这样看,两个类的互相包含头文件肯定出错,那么如何解决这种情况呢?一种办法是在A类中包含B类的头文件,在B类中前置盛明A类,不过注意的是B类使用A类变量必须通过指针来进行,具体见拙文:类互相包含的办法。为何不能前置声明只能通过指针来使用?通过分析这个实际上我们可以得出前置声明和包含头文件的区别。我们把CLayer类的代码改动一下,再看下面的代码:

然后编译,出现一个编译警告:>f:/mytest/mytest/src/testunix/layer.cpp(16) : warning C4150: 删除指向不完整“CSymbol”类型的指针;没有调用析构函数

1> f:/mytest/mytest/src/testunix/layer.h(9) : 参见“CSymbol”的声明

看到这个警告,我想你一定悟到了什么。下面我说说我的结论:类的前置声明和包含头文件的区别在于类的前置声明是告诉编译器有这种类型,但是它没有告诉编译器这种类型的大小、成员函数和数据成员,而包含头文件则是完全告诉了编译器这种类型到底是怎样的(包括大小和成员)。这下我们也明白了为何前置声明只能使用指针来进行,因为指针大小在编译器是确定的。上面正因为前置声明不能提供析构函数信息,所以编译器提醒我们:CSymbol”类型的指针没有调用析构函数。如何解决这个问题呢?在Layer.cpp加上#include "Symbol.h"就可以消除这个警告。

分享到:
评论

相关推荐

    C++_关于声明,定义,类的定义,头文件作用

    C++_关于声明,定义,类的定义,头文件作用

    C语言头文件 DIR C语言头文件 DIR

    C语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言头文件 DIRC语言...

    MFC类目录及头文件

    MFC类目录及头文件 MFC类目录及头文件 MFC类目录及头文件

    C语言头文件 MEM C语言头文件 MEM

    C语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言头文件 MEMC语言...

    C语言头文件 NB30 C语言头文件 NB30

    C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言头文件 NB30C语言...

    C语言头文件 OLE C语言头文件 OLE

    C语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言头文件 OLEC语言...

    C语言头文件 temp C语言头文件 temp

    C语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言头文件 tempC语言...

    DIB图像处理类(包括头文件和cpp文件)

    图像处理书中常见的DIB图像处理类,包括了头文件和源文件

    C语言头文件 NEW.H

    C语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 NEW.HC语言头文件 ...

    keil添加STC完整教程和资料,包含头文件和数据库

    keil添加STC完整教程和资料,包含头文件和数据库

    C语言头文件 MATH C语言头文件 MATH

    C语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言头文件 MATHC语言...

    C语言头文件 DATA C语言头文件 DATA

    C语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言头文件 DATAC语言...

    MFC常用类的对应的头文件

    MFC常用类的对应的头文件,常用的类和头文件的对应关系,省得找不到头文件了.

    C语言头文件 DOS C语言头文件 DOS

    C语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言头文件 DOSC语言...

    C语言头文件 RTM C语言头文件 RTM

    C语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言头文件 RTMC语言...

    C语言头文件 NEW C语言头文件 NEW

    C语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言头文件 NEWC语言...

    C语言头文件 GLU C语言头文件 GLU

    C语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言头文件 GLUC语言...

    C语言头文件 MAP C语言头文件 MAP

    C语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言头文件 MAPC语言...

    c语言常用头文件,头文件和包括的主要函数分类

    总结了c语言常用的头文件 常用头文件分类, 常用的函数及其所在的头文件描述

    C语言头文件 RPC C语言头文件 RPC

    C语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言头文件 RPCC语言...

Global site tag (gtag.js) - Google Analytics