C++中头文件(.h)和源文件(.hpp)应该写什么(二)

    在C++编程过程中,随着项目的越做越大,代码也会越来越多,并且难以管理和分析。于是,在C++中就要分出了头(.h)文件和实现(.cpp)文件,并且也有了Package的概念。

    简单的讲,一个Package就是由同名的.h和.cpp文件组成,当然可以少其中任意一个文件:只有.h文件的Package可以是接口或模板(template)的定义;只有.cpp文件的Package可以是一个程序的入口。

    这里讲的还是关于 .h文件和 .cpp文件

    知道Package只是相对比较宏观的理解:我们在项目中以Package为编辑对象来扩展和修正我们的程序。编写代码时具体到应该把什么放在 .h文件,又该什么放在 .cpp文件中。

    大部分的解释都太笼统:申明写在 .h文件,定义实现写在 .cpp文件。这个解释没有差错,但是真正下手起来,又会迷惑。

    为了不忘记将其总结一下:

概览

非模板类型(None-template)模板类型(template)
头文件(.h)1、全局变量声明(带extern限定符)  
2、全局函数的声明           
3、带inline限定符的全局函数的定义  
4、类的定义                
5、类函数成员和数据成员的申明(在类内部)   
6、类定义内的函数定义(相当于inline)
7、带static const限定符的数据成员在类内部的初始化
8、带inline限定符的类定义外的函数定义       
1、带inline限定符的全局模板函数的申明和定义
2、模板类的定义
3、模板类成员的申明和定义(定义可以放在类内或者类外,类外不需要写inline)
实现文件(.cpp)1、全局变量的定义(及初始化)
2、全局函数的定义
3、类函数成员的定义
4、类带static限定符的数据成员的初始化
(无)

*申明:declaration
*定义:definition

头文件

头文件的所有内容,都必须包含在

#ifndef {Filename} 
#define {Filename} 

//{Content of head file} 

#endif

这样才能保证头文件被多个其他文件引用(include)时,内部的数据不会被多次定义而造成错误

inline限定符

在头文件中,可以对函数用inline限定符来告知编辑器,这段函数非常的简单,可以直接嵌入到调用定义之处。

当然inline的函数并不一定会被编辑器作为inline来实现,如果函数过于复杂,编辑器也会拒绝inline

因此简单来说,代码最好短到3~5行的才作为inline。有循环,分支,递归的函数都不要用作inline

对于在类定义内定义实现的函数,编辑器自动当做有inline请求(也是不一定的inline的)。因此在下边,我把带有inline限定符的函数成员和写在类定义体内的函数成员统称为“要inline的函数成员”

非模板类型

全局类型

就像全面笼统的话来讲:申明写作 .h文件。

对于函数来讲,没有实现体的函数,就相当于是申明;而对于数据类型(包括基本类型和自定义类型)来说,其申明就需要用extern来修饰。

然后在 .cpp文件里定义、实现或初始化这些全局函数和全局变量。

注:一般不使用全局函数和全局变量。

自定义类型

对于自定义类型,包括类(class)和结构体(struct),它们的定义都是放在 .h文件中。其成员的申明和定义就比较复杂,不过看上边的表格,还是比较清晰的。

自定义成员

函数成员无论是否带有static限定符,其申明都放在 .h文件的类定义内部。

对于要用inline的函数成员其定义放在**.h文件;其他函数的实现都放在.cpp**文件中。

数据成员

数据成员的申明与定义都是放在 .h文件的类定义内部。对于数据类型,关键问题是其初始化要放在什么地方进行。

对于只含有static限定符的数据成员,它的初始化要放在 .cpp文件中。因为它是所有类对象共有的,因此必须对它做合适的初始化。

对于只含有const限定符的数据成员,它的初始化只能在构造函数的初始化列表中完成。因为它是一经初始化就不能重新赋值,因此它也必须进行合适的初始化。

对于既含有static限定符,又含有const限定符的数据成员,它的初始化和定义同时进行。它也是必须进行合适的初始化

对于既没有static限定符,又没有const限定符的数据成员,它的值只针对本对象可以随意修改,因此我们并不在意它的初始化什么时候进行。

模板类型

C++ 中,模板是一把开发利器,它与C#Java的泛型很类似,却又不尽相同。以前,我一直只觉得像泛型,模板这种东西我可能这一辈子都不可能需要使用到。但是模板的强大,也让我真正要如何去使用模板,更进一步是如何去设计模板。不过在此就不多说。

对于模板,最重要的一点,就是在定义它的时候,编辑器并不会对它进行编译,因为它没有一个实体可用。

只有模板被具体化(specialization)之后(用在特定的类型上),编辑器才会根据具体的类型对模板进行编译。

所以才定义模板的时候,会发现编译器基本不会报错,也做不出只能提示。但是当它被具体用在一个类上之后,错误就会大片大片的出现,却往往无法准确定位。

因此设计模板就有设计模板的一套思路和方式。

因为模板的这种特殊性,它并没有自己的准确定义,因为我们不能把它放在 .cpp文件中,而是把他们全部放在 .h文件中进行书写。这也是为了再模板具体化的时候,能够让编译器可以找到模板的所有定义在哪里,以便真正的定义方法。

至于模板类函数成员的定义放在哪里,一般放在类定义之外,因为这样当你看类的时候,一目了然地知道有哪些方法和数据;用vs的时候查看其标准库的实现,都是放在类内部的。

参考

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值