解决Visual C++ 中相互包含头文件的问题

2024-09-07 15:08

本文主要是介绍解决Visual C++ 中相互包含头文件的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在编MFC应用程序时,经常会遇到头文件相互包含的问题,很是苦恼,于是便求助于强大的CSDN,得到如下答案:

 

方法一:利用友元类
 
我一共有两个类,由于要在两个类的头文件里互相应用对方,所以,在每一个类的头文件里面现包含另一个类的头文件,然后在该类的定义中声明另一个类为友元类。如下:
   #include "B.h"
 
   class CA: public CDialog
   {
       friend class CB;
       public:
        CB* m_b;  //注意一定要是指针类型
   }
 
在另一个类中可以这样声明:
 
   #include "A.h"
   class CB: public CDialog
   {
      friend class CA;

      public:
        CA * m_a;   //注意一定要是指针类型
   }
   
最后关键的是在每一个类的构造函数里 new 一个对方的类出来就ok了!
 
   方法二:
   
我一共有两个类,由于要在两个类的头文件里互相应用对方,所以,在每一个类的头文件里面现包含另一个类的头文件,然后在该类的定义中声明另一个类为友元类。如下:
   #include "B.h"
 
   class CA: public CDialog
   {
       friend class CB;
       public:
        CB* m_b;  //注意一定要是指针类型
   }
 
在另一个类中可以这样声明:
 
   class CA;
   class CB: public CDialog
   {
      public:
        CA * m_a;   //注意一定要是指针类型
   }
   
在cb.cpp文件中包含头文件
#include "ca.h"
 
最后关键的是在每一个类的构造函数里 new 一个对方的类出来就ok了!


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/DavidHsing/archive/2007/11/09/1876788.aspx

 

常见错误为:

error C2501: 'A' : missing storage-class or type specifiers

error C2079: 'b' uses undefined class 'B'

 

除此之外,还有另外一篇文章:

 所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数。
    一般情况下,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中的部分称为类的定义。如果大家对这三个词有不同的理解,请按照自己的本意
把这三个词换成相应的词来理解。

这篇关于解决Visual C++ 中相互包含头文件的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145392

相关文章

解决RocketMQ的幂等性问题

《解决RocketMQ的幂等性问题》重复消费因调用链路长、消息发送超时或消费者故障导致,通过生产者消息查询、Redis缓存及消费者唯一主键可以确保幂等性,避免重复处理,本文主要介绍了解决RocketM... 目录造成重复消费的原因解决方法生产者端消费者端代码实现造成重复消费的原因当系统的调用链路比较长的时

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

kkFileView启动报错:报错2003端口占用的问题及解决

《kkFileView启动报错:报错2003端口占用的问题及解决》kkFileView启动报错因office组件2003端口未关闭,解决:查杀占用端口的进程,终止Java进程,使用shutdown.s... 目录原因解决总结kkFileViewjavascript启动报错启动office组件失败,请检查of

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么

SpringBoot 异常处理/自定义格式校验的问题实例详解

《SpringBoot异常处理/自定义格式校验的问题实例详解》文章探讨SpringBoot中自定义注解校验问题,区分参数级与类级约束触发的异常类型,建议通过@RestControllerAdvice... 目录1. 问题简要描述2. 异常触发1) 参数级别约束2) 类级别约束3. 异常处理1) 字段级别约束

java内存泄漏排查过程及解决

《java内存泄漏排查过程及解决》公司某服务内存持续增长,疑似内存泄漏,未触发OOM,排查方法包括检查JVM配置、分析GC执行状态、导出堆内存快照并用IDEAProfiler工具定位大对象及代码... 目录内存泄漏内存问题排查1.查看JVM内存配置2.分析gc是否正常执行3.导出 dump 各种工具分析4.