C++的头文件和实现文件详解


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

对于以C起步,C#作为“母语”的我刚开始跟着导师学习C++对这方面还是感到很模糊。虽然我可以以C的知识面对C++的语法规范,用C#的思想领悟C++中类的使用。但是C#中定义和实现是都在一个文件中(其实都是在类里面),而使用C的时候也只是编程的刚刚起步,所写的程序也只要一个文件就够了。因此对于C++的Package理解以及.h文件和.cpp文件的总是心存纠结。

幸好导师有详细的PPT让我了解,一次对于Package的认识就明白多了。简单讲,一个Package就是由同名的.h和.cpp文件组成。当然可以少其中任意一个文件:只有.h文件的Package可以是接口或模板(template)的定义;只有.cpp文件的Package可以是一个程序的入口。

当然更具体详细的讲解,欢迎下载导师的教学PPT-Package来了解更多。

不过我在这里想讲的还是关于.h文件和.cpp文件

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

虽然Google给了我很多的链接,但是大部分的解释都太笼统了:申明写在.h文件,定义实现写在.cpp文件。这个解释没有差错,但是真正下手起来,又会发现不知道该把代码往哪里打。

于是我又把这个问题抛给了导师,他很耐心地给我详详细细地表述了如何在C++中进行代码分离。很可惜,第一次我听下了,但是没有听太懂,而且本来对C++就了解不深,所以也没有深刻的印象。

经过几个项目的试炼和体验之后,我又拿出这个问题问导师,他又一次耐心地给我讲解了一遍(我发誓他绝对不是忘记了我曾经问过同样的问题),这次我把它记录了下来。

为了不再忘记,我将它们总结在这里。

概览

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

*申明: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文件中进行书写。这也是为了在模板具体化的时候,能够让编译器可以找到模板的所有定义在哪里,以便真正的定义方法。

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

可能是我习惯了C#的风格,我比较喜欢把它们都写在类内部,也因为在开发过程中,所使用的编辑器都有一个强大的功能:代码折叠。

当然还有其他原因就是写在类外部,对于每一个函数成员的实现都需要把模板类型作为限定符写一遍,把类名限定符也要写一遍。



相关阅读:
ASP.NET中TimeSpan的用法实例解析
Win10 最新预览版10061已发放 暂不支持升级
Android编程之SurfaceView实例详解
PHP使用pear实现mail发送功能 windows环境下配置pear
用JS动态改变表单form里的action值属性的两种方法
PHP实现自动对图片进行滚动显示的方法
Android Camera开发手电筒功能
Win10 10122预览版 更新内容大全
JavaScript显示表单内元素数量的方法
jquery 页面滚动到指定DIV实现代码
Win10启动慢的很慢该怎么办? win10启动加速的全面教程
c#使用wmi查询usb设备信息示例
用HTML5中的Canvas结合公式绘制粒子运动的教程
CSS中怎么让DIV居中亲自实验得出的结论
快速导航
PHP MySQL HTML CSS JavaScript MSSQL AJAX .NET JSP Linux Mac ASP 服务器 SQL jQuery C# C++ java Android IOS oracle MongoDB SQLite wamp 交通频道 作文范文 沙城-敦煌 永泰-漳浦 安多-拉萨 都江堰-郫县 临汾-白涧 扶余北-泰安 青州市-平原 安顺-桐梓 藁城-定边 牡丹江-泰康 正镶白旗-开鲁 镇江-合川 昌平北-超梁沟 高平-文水 郴州西-恩施 古莲-乌鲁布铁 株洲-无锡 北安-横道河子 东明村-敖来 平遥-兰州西 葛根庙-赤峰 广州-十堰 二连-赛乌苏 灵石-唐山 昌图-柳林南 成吉思汗-香兰 霸州西-扶余北 亳州-昌图 融安-文地 余粮堡-双辽 石山-绕阳河 扎鲁特-沈阳 萨拉齐-绥德 镇远-定州 明城-杨村 兖州-常州 向塘-沁县 桥北-陈相屯 滨海-北戴河 漯河西-烟台 青岛-汉中 郑州-赤壁 黄石-开江 新沂-泰州 乌鲁布铁-古源 沧州西-德惠西 咸宁北-永州 昭通-龙游 安图-五常 丰城-永州 临城-聊城 达州-龙岩 定南-蕲春 集宁南-上店 汇流河-里木店 武安-辛集 阿克苏-山丹 诏安-福安 肃宁-阜阳 扎音河-孙吴 郴州-新沂 三关口-平凉 宜宾-田梁子 昌图西-沈阳北 灵宝-荆门 溧阳-砀山南 阿寨-代湾 扬州-仙桃西 海林-一面坡 汨罗-西安 热水-北票南 塔尔根-伊拉哈 兴凯-柳毛 株洲-枣强 德州-卢龙 交城-太原 遂宁-昆山南 景泰-中宁 大陆号-化德 轵城-莲东 谁哪提供烟台到东营的汽车的发车时间有几班
从百草园到三味书屋
从沈阳桃仙机场到长春市,如何乘车最方便
从太原到平遥火车有几点的了票价多少了
从湖南长沙到河南林州怎么坐车
今天包头的气温达到了零下18度,我是不是应该扔掉工作回老家
江津先锋的新修建的农村公路有哪些.到大屋基那截的工程总造价
从青岛到沈阳的高铁有么?
上海青浦到南京溧水明觉镇怎么坐车,
金华到中山有没有直达列车火车
从江洲镇到沙河街镇怎么坐车
扬州在那个站能买到阜阳的汽车票
常熟到高邮有没有直达车如果没有,除了在车站买到扬州的
在广西有到赣州的直达车吗火车,汽车都可以
杭州望江门到施家桥公交路线怎么走
从北京到四川绵阳最快的火车
阜阳到澧县怎么走最快
哪位高人请告诉我柳永墓到底在什么地方?
晚上到杭州,第二天白天玩儿完后到乌镇住宿,请牛人帮忙设计
漳州到福州的票价钱数和时间表
从商丘到郑州的物流哪个送货上门
深圳列车站 石岩大树林
谁有梭织和针织面料的合同,我要到工厂进面料,在网上查了很久
泰州到南京红山动物园自己开车怎么坐车?
郑州五龙口租房是多少钱啊
西宁有到上海的列车吗
河南工程学院 郑州市桐柏路62号 从列车火车站怎么坐车啊
肇庆宋文化作文
邯郸现在有到郑州机场的大巴吗
南通到洛阳,怎么走方便

Copyright © 2016 phpStudy |