浅析VC++中的头文件包含问题_C 语言

在一些大的工程中,可能会包含几十个基础类,免不了之间会互相引用(不满足继承关系,而是组合关系)。也就是需要互相声明。好了,这时候会带来一些混乱。如果处理得不好,会搞得一团糟,根据我的经验,简单谈谈自已的处理办法:

编码时,我们一般会尽量避免include头文件,而是采用声明 class XXX。但有时候还是必须用Include头文件,那么,两者的划分在于什么呢?

应该是很明确的,但书上好像都少有提及。

首先:
我们要明白为什么要用声明取代头文件包含:对了,是为了避免无必要的重编译(在头文件发生变更时)。工程较大,低速机,或基础类经常变更(不合理的设计吧),编译速度还是会在意的,另外,更为重要的是,采用声明可降低代码(class)之间的藕合度,这也是面向对象设计的一大原则。

二:一般原则:
a. 头文件中尽量少include, 如果可以简单申明 class clsOld; 解决,那最好。减少没有必要的include;
b. 实现文件中也要尽量少include,不要include没有用到的头文件。

三:那什么时候可以只是简单声明class clsOld呢?
简单的说:不需要知道clsOld的内存布局的用法都可以(静态成员除外),也就是讲如果是指针或引用方式的都行。
比如:
clsOld * m_pOld;    //指针占4个字节长
clsOld & test(clsOld * pOld) {return *pOld};
一切OK。

四:什么时候不能简单声明class clsOld,必须include呢?
不满足三的情况下:
比如:
clsOld m_Objold;  //不知道占据大小,必须要通过它的具体声明来计算
原因很简单,想想你要计算sizeof(classNew),但连clsOld的size都不知道,编译器显然会无能为力。

特殊情况:
int test() { return clsOld::m_sInt;}
静态成员调用,想来应该是不需要知道内存布局的,但因为需要知道m_sInt是属于clsOld命名空间的,如果只声明class xxx显然是不足以说明的,所以必须包含头文件。

综上所述,我有以下几点建议:
1:
如果有共同相关依赖(必须include)的类,比如 A,B都依赖D 可以放在一起,然后直接 Include "d" 类的使用者只需关心与本类暴露出的相关类型,内部用到的类型不用去管(不用自已去include d)。这样给出的class,调用者才更好用(不用去看代码查找,是不是还需要包含其它头文件)。

2:如果A类依赖D B类不依赖D,可以把它们分开两个头文件。各自Include。这样可避免当D发生变化时,避免不必要重编译。

3:类中尽量采用指针或引用方式调用其它类,这样就可以只声明class xxx了。并且这也符合资源最优利用,更利于使用多态。

-------------------------------
既然使用了包含文件,为什么还要在class CMainFrame前添加"class CViewerView;"等代码?如果用包含文件代替它,行不行?  很多Visual C++书籍对这些问题避而不谈,但实际上这是一个重要的问题。如果不能理解上述代码,我们很可能为无法通过编译而大伤脑筋。这些问题的出现是基于这样的一些事实:在我们用标准C/C++设计程序时,有一个原则即两个代码文件不能相互包含,而且多次包含还会造成重复定义的错误。为了解决这个难题, Visual C++使用#pragma once来通知编译器在生成时只包含(打开)一次,也就是说,在第一次#include之后,编译器重新生成时不会再对这些包含文件进行包含(打开)和读取,因此我们看到在用向导创建的所有类的头文件中有#pragma once语句就不会觉得奇怪了。然而正是由于这个语句而造成了在第二次#include后编译器无法正确识别所引用的类。因此,我们在相互包含时还需要加入类似class CViewerView这样的语句来通知编译器这个类是一个实际的调用

时间: 2024-09-23 22:36:43

浅析VC++中的头文件包含问题_C 语言的相关文章

解析VC中预编译头文件的深入分析_C 语言

一.为什么预编译头文件:预编译头的概念: 所谓的预编译头就是把一个工程中的那一部分代码,预先编译好放在一个文件里(通常是以.pch为扩展名的),这个文件就称为预编译头文件这些预先编译好的代码可以是任何的C/C++代码,甚至是inline的函数,但是必须是稳定的,在工程开发的过程中不会被经常改变.如果这些代码被修改,则需要重新编译生成预编译头文件.注意生成预编译头文件是很耗时间的.同时你得注意预编译头文件通常很大,通常有6-7M大.注意及时清理那些没有用的预编译头文件.也许你会问:现在的编译器都有

vc中SendMessage自定义消息函数用法实例_C 语言

本文实例讲述了vc中SendMessage自定义消息函数用法,分享给大家供大家参考.具体如下: SendMessage的基本结构如下: 复制代码 代码如下: SendMessage(     HWND hWnd,  //消息传递的目标窗口或线程的句柄.     UINT Msg, //消息类别(这里可以是一些系统消息,也可以是自己定义,下文具体介绍,)     WPARAM wParam, //参数1 (WPARAM 其实是与UINT是同种类型的,   //在vc编译器中右键有个"转到WPARA

VC++中图像处理类CBitmap的用法_C 语言

VC++中图像处理类CBitmap的用法 class CBitmap : public CGdiObject { DECLARE_DYNAMIC(CBitmap) public: static CBitmap* PASCAL FromHandle(HBITMAP hBitmap); // Constructors CBitmap(); BOOL LoadBitmap(LPCTSTR lpszResourceName); BOOL LoadBitmap(UINT nIDResource); BOO

浅析C++中模板的那点事_C 语言

1.什么是模板 假设现在我们完成这样的函数,给定两个数x和y求式子x^2 + y^2 + x * y的值 .考虑到x和y可能是 int , float 或者double类型,那么我们就要完成三个函数: int fun(int x,int y);float fun(float x,float y);double fun(double x,double y); 并且每个fun函数内部所要完成的操作也是极其的相似.如下: 复制代码 代码如下: int fun(int x,int y){    int

浅析C++中memset,memcpy,strcpy的区别_C 语言

复制代码 代码如下: #include <stdio.h>#include <stdlib.h>#include <string.h>#include <assert.h> //memcpy:按字节复制原型:extern void* memcpy(void *dest,void *src,unsigned int count)//功能:由src所指内存区域复制count个字节到dest所指的内存区域://同strcpyvoid *memcpy_su(void

浅析c++中new和delete的用法_C 语言

new和delete运算符用于动态分配和撤销内存的运算符 new用法: 1.开辟单变量地址空间1)new int;  //开辟一个存放数组的存储空间,返回一个指向该存储空间的地址.int *a = new int 即为将一个int类型的地址赋值给整型指针a.  2)int *a = new int(5) 作用同上,但是同时将整数赋值为5 2. 开辟数组空间一维: int *a = new int[100];开辟一个大小为100的整型数组空间二维: int **a = new int[5][6]三

c语言头文件包含问题-关于头文件包含的问题,请教大家!

问题描述 关于头文件包含的问题,请教大家! 程序源文件中有两个头文件,头文件A中定义了一个结构体类型_tag_addr,并在头文件开头使用了#ifnodef #define预编译宏;头文件B中定义了一个结构体类型_tag_bddr,也在头文件开头使用了预编译宏,现在的问题是我要在头文件A中声明一个_tag_bddr类型的变量,在头文件B中声明一个_tag_addr类型的变量,所以要在头文件A开头包含头文件B,也要在头文件B中包含头文件A,但是这样做编译时头文件A报错,说是没有_tag_bddr类

程序设计方式 之 嵌套头文件包含方式

       一直以来写程序有个习惯,喜欢把常用的STL类,或者其他常用的类,变量,宏等定义到一个文件内,然后在使用其中一个类的地方包含这个文件.一直再使用,也一直存在困惑,这种设计方式的能否放心大胆的使用,对它始终心存畏惧,所有这些促使我完成这篇文章,并且经过种种测试,有足够的信心继续使用这种设计方式.        操作如下 定义base.h文件,包含基本的STL类,并且通过typedef建立不同的映射关系,以便减少不同的文件出现过多vector<string>之类的声明方式.当需要使用v

xcode-vtk 头文件包含的相关问题

问题描述 vtk 头文件包含的相关问题 编译好的vtk中是否有include文件夹?我在调用vtk的头文件时,如下面代码所示: #include ""vtkDICOMImageReader.h""#include ""vtkPiecewiseFunction.h""#include ""vtkColorTransferFunction.h""#include ""vt