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

 更新时间:2013年09月16日 08:57:16   作者:  
类中尽量采用指针或引用方式调用其它类,这样就可以只声明class xxx了。并且这也符合资源最优利用,更利于使用多态

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

编码时,我们一般会尽量避免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这样的语句来通知编译器这个类是一个实际的调用

相关文章

  • C++深复制和浅复制讲解

    C++深复制和浅复制讲解

    这篇文章主要介绍了C++深复制和浅复制讲解,C++中深复制和浅复制最大的区别在“类包含指针类型的数据成员”时,下面感兴趣的小伙伴和小编一起进入文章了解更多相关内容吧
    2022-03-03
  • 使用C++中的ADO对SQLite进行增删改查

    使用C++中的ADO对SQLite进行增删改查

    本文将介绍如何使用C++的ADO (ActiveX Data Objects)对SQLite数据库进行增删改查操作,文中有详细的代码示例,需要的朋友可以参考下
    2023-06-06
  • C语言操作符超详细讲解下篇

    C语言操作符超详细讲解下篇

    C 语言提供了丰富的操作符,有:算术操作符,移位操作符,位操作符,赋值操作符,单目操作符,关系操作符,逻辑操作符,条件操作符等。本篇为第二篇,让我们通读本篇来详细了解吧
    2022-04-04
  • C++实现查找中位数的O(N)算法和Kmin算法

    C++实现查找中位数的O(N)算法和Kmin算法

    这篇文章主要介绍了C++实现查找中位数的O(N)算法和Kmin算法,对于C++程序算法设计有一定的借鉴价值,需要的朋友可以参考下
    2014-09-09
  • xxx_cast类型转换的实现方法

    xxx_cast类型转换的实现方法

    下面小编就为大家带来一篇xxx_cast类型转换的实现方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • c语言轻松实现猜数字小游戏

    c语言轻松实现猜数字小游戏

    猜数字是兴起于英国的益智类小游戏,起源于20世纪中期,一般由两个人或多人玩,也可以由一个人和电脑玩。游戏规则为一方出数字,一方猜,今天我们来用C实现这个游戏案例
    2022-04-04
  • 数据结构之AVL树详解

    数据结构之AVL树详解

    这篇文章主要介绍了数据结构之AVL树详解,本文非常细致的讲解了AVL树的基础知识、AVL树的旋转操作、AVL数的插入和删除操作等,需要的朋友可以参考下
    2014-08-08
  • C语言实现简易版扫雷小游戏

    C语言实现简易版扫雷小游戏

    这篇文章主要为大家详细介绍了C语言实现简易版扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • C++ Boost Parameter超详细讲解

    C++ Boost Parameter超详细讲解

    Boost是为C++语言标准库提供扩展的一些C++程序库的总称。Boost库是一个可移植、提供源代码的C++库,作为标准库的后备,是C++标准化进程的开发引擎之一,是为C++语言标准库提供扩展的一些C++程序库的总称
    2022-11-11
  • C++实现动态绑定代码分享

    C++实现动态绑定代码分享

    对于C++动态绑定的理解,就是编译器用静态分析的方法加上虚拟函数的设计实现在程序运行时动态智能执行正确虚拟函数的技术。要彻底理解动态绑定,只需要掌握两点,一是编译器的静态编译过程,二是虚拟函数的基本知识。只要有了这两点理解,任何动态绑定的分析都是很容易的
    2015-11-11

最新评论