VC++开发中完美解决头文件相互包含问题的方法解析

 更新时间:2013年09月16日 09:11:21   作者:  
本文中,为了叙述方便,把class AClass;语句成为类AClass的声明,把class AClass开始的对AClass的类成员变量、成员函数原型等的说明称为类的定义,而把在CPP中的部分称为类的定义

所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数。

一般情况下,C/C++要求所有的类型必须在使用前被定义,但是在一些特殊情况下,这种要求无法满足,例如,在类CMyView中保留了一个非模式对话框对象指针,该对象用于显示/修改一些信息。为了实现对话框"应用"按钮,把对话框做的修改立刻更新到view界面上,为此,需要在对话框类中需要保存view类的指针,这样定义关系就变成如下的代码:

复制代码 代码如下:

   #ifndef __MYVIEW_H__
   #define __MYVIEW_H__
   //这是view类的头函数
   #include "MyDialog.h"
   class CMyView::public CView
   {
   protected:
       CMyDialog * pDlg;
       //这里是其他定义
   };
   #endif

   #ifndef __MYDIALOG_H__
   #define __MYDIALOG_H__
   //这是对话框类的定义
   #include "MyView.h"
   class CMyDialog::public CDialog
   {
       protected:
CMyView * pView;
//其他定义
   };
   #endif

从编译器角度看,编译MyDialog.CPP时,系统首先定义宏__MYDIALOG_H__,然后包含MyView.h,MyView.h中的#include "MyDialog.h"由于__MYDIALOG_H__已经定义,所以不再起作用。在CMyView类的声明中,CMyDialog* pDlg ;就会让编译器产生"CMyDialog"类型没有定义之类的错误,编译MyView.CPP文件出现的错误可以类似得到。   

一般的情况,类A和类B需要彼此互相引用,这样必然有一个类会先被定义,而另外一个类后被定义,这样在先被定义的类引用后被定义的类的时候,就导致了所谓的超前引用。

超前引用导致的错误有以下几种处理办法:

1) 使用类声明
在超前引用一个类之前,首先用一个特殊的语句说明该标识符是一个类名,即将被超前引用。其使用方法是:
a)  用class ClassB;声明即将超前引用的类名
b)  定义class ClassA
c)  定义class ClassB;
d)  编制两个类的实现代码。
上述方法适用于所有代码在同一个文件中,一般情况下,ClassA和ClassB分别有自己的头文件和cpp文件,这种

方法需要演变成:
a) 分别定义ClassA和ClassB,并在cpp文件中实现之
b) 在两个头文件的开头分别用class ClassB;和class ClassA;声明对方
c) 在两个cpp文件中分别包含另外一个类的头文件
NOTE:这种方法切记不可使用类名来定义变量和函数的变量参数,只可用来定义引用或者指针。    

2) 使用全局变量
由于全局变量可以避免超前引用,不用赘述。我的习惯是,把类对象的extern语句加在该类头文件的最后,大家喜欢怎样写那都没有什么大问题,关键是保证不要在头文件中胡乱包含。

3) 使用基类指针。
这种方法是在引用超前引用类的地方一律用基类指针。而一般情况下,两个互相引用的类并不涉及其基类,因此不会造成超前引用。以开始的例子说:在CMyDialog类中用CView*代替CMyView*,在CMyView类中用CDialog*代替CMyDialog*,这样必然不会造成超前引用。

说明:本文中,为了叙述方便,把class AClass;语句成为类AClass的声明,把class AClass开始的对AClass的类成员变量、成员函数原型等的说明称为类的定义,而把在CPP中的部分称为类的定义。如果大家对这三个词有不同的理解,请按照自己的本意把这三个词换成相应的词来理解。

ps:我是用第一种方法解决问题的。

相关文章

  • 利用C++求绝对值的几种方法例子

    利用C++求绝对值的几种方法例子

    相信大家在学习C++时,应该都有做过求绝对值的题目,下面这篇文章主要给大家介绍了关于利用C++求绝对值的几种方法例子,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-04-04
  • C++私有继承(三)

    C++私有继承(三)

    这篇文章主要介绍了C++私有继承(三),前面的文章我们已经介绍过了C++私有继承(一)和(二),下面小编就继续基于之前的内容继续向大家介绍C++私有继承,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-02-02
  • C++获取当前时间戳的几种常用方法

    C++获取当前时间戳的几种常用方法

    在我们写程序时,通过写时间戳可以方便我们进行日志记录、调试、计算程序运行时间、缓存过期控制等,因此下面介绍使用C++代码获取时间戳的方法以及一些常见的应用场景,需要的朋友可以参考下
    2025-08-08
  • C++中的STL常用算法之遍历算法详解

    C++中的STL常用算法之遍历算法详解

    这篇文章主要介绍了C++中的STL常用算法之遍历算法详解,ransform() 可以将函数应用到容器的元素上,并将这个函数返回的值保存到另一个容器中,它返回的迭代器指向输出容器所保存的最后一个元素的下一个位置,需要的朋友可以参考下
    2023-12-12
  • 头文件不宜定义变量的原因全面解析

    头文件不宜定义变量的原因全面解析

    以下是对头文件不宜定义变量的原因进行了详细的分析介绍,需要的朋友可以过来参考下
    2013-09-09
  • C语言详细分析讲解关键字const与volatile的用法

    C语言详细分析讲解关键字const与volatile的用法

    在C语言中,我们经常会见到const和volatile这两个关键字,那么我们今天就来介绍下这两个关键字,提起 const 关键字,我们可能首先想到的是经过它修饰的变量便是常量了。其实我们这种想法是错误的,其实 const 修饰的变量是只读的,其本质还是变量
    2022-04-04
  • C语言中static与sizeof查缺补漏篇

    C语言中static与sizeof查缺补漏篇

    static在修饰变量的时候,如果是修饰全局变量,则跟全局变量功能一样;如果是修改局部变量,则每次调用的时候,保持着上一次的值;而sizeof是用来判断一个变量及数据类型所占字节数的,下面我们详细来看看
    2022-07-07
  • C++趣味算法之侦探推理

    C++趣味算法之侦探推理

    本文详细讲解了C++趣味算法之侦探推理,文中通过示例代码介绍的非常详细。对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-12-12
  • C++中约数定理的实例详解

    C++中约数定理的实例详解

    这篇文章主要介绍了C++中约数定理的实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • 基于内核线程的创建、使用和退出以及延时宏的补充说明介绍

    基于内核线程的创建、使用和退出以及延时宏的补充说明介绍

    本篇文章是对内核线程的创建、使用和退出以及延时宏的补充说明介绍进行了叙述。需要的朋友参考下
    2013-05-05

最新评论