如何理解C++中的.h文件和.cpp文件

  • 一、源文件如何根据#include来关联头文件
  • 二、头文件如何来关联源文件
  • 三、声明与定义的区分:
    • 综上所诉

  建立一个以类为名字的XX.h文件,声明类,再建立一个相同名字的XX.cpp文件(要#include “XX.h”),实现类中的函数, 在有main 函数的.cpp里声明函数,建一个与函数名一样的.cpp文件,实现该函数;并且要 #include “XX.h”

一、源文件如何根据#include来关联头文件

  1.系统自带的头文件用尖括号括起来,这样编译器会在系统文件目录下查找。

#include <xxx.h>

  2.用户自定义的文件用双引号括起来,编译器首先会在用户目录下查找,然后在到C++安装目录(比如VC中可以指定和修改库文件查找路径,Unix和Linux中可以通过环境变量来设定)中查找,最后在系统文件中查找。

#include “xxx.h”

二、头文件如何来关联源文件

  这个问题实际上是说,已知头文件“a.h”声明了一系列数,“b.cpp”中实现了这些函数,那么如果我想在“c.cpp”中使用“a.h”中声明的这些在“b.cpp”中实现的函数,通常都是在“c.cpp”中使用#include“a.h”,那么c.cpp是怎样找到b.cpp中的实现呢?

  • 其实.cpp和.h文件名称没有任何直接关系,很多编译器都可以接受其他扩展名。比如偶现在看到偶们公司的源代码,.cpp文件由.cc文件替代了。
  • 在Turbo C中,采用命令行方式进行编译,命令行参数为文件的名称,默认的是.cpp和.h,但是也可以自定义为.xxx等等。
  • 谭浩强老师的《C程序设计》一书中提到,编译器预处理时,要对#include命令进行“文件包含处理”:将file2.c的全部内容复制到#include“file2.c”处。这也正说明了,为什么很多编译器并不care到底这个文件的后缀名是什么—-因为#include预处理就是完成了一个“复制并插入代码”的工作。
  • 编译的时候,并不会去找b.cpp文件中的函数实现,只有在link的时候才进行这个工作。我们在b.cpp或c.cpp中用#include“a.h”实际上是引入相关声明,使得编译可以通过,程序并不关心实现是在哪里,是怎么实现的。源文件编译后成生了目标文件(.o或.obj文件),目标文件中,这些函数和变量就视作一个个符号。在link的时候,需要在makefile里面说明需要连接哪个.o或.obj文件(在这里是b.cpp生成的.o或.obj文件),此时,连接器会去这个.o或.obj文件中找在b.cpp中实现的函数,再把他们build到makefile中指定的那个可以执行文件中。
  • 在Unix下,甚至可以不在源文件中包括头文件,只需要在makefile中指名即可(不过这样大大降低了程序可读性,是个不好的习惯哦_)。在VC中,一帮情况下不需要自己写makefile,只需要将需要的文件都包括在project中,VC会自动帮你把makefile写好。
  • 通常,编译器会在每个.o或.obj文件中都去找一下所需要的符号,而不是只在某个文件中找或者说找到一个就不找了。因此,如果在几个不同文件中实现了同一个函数,或者定义了同一个全局变量,链接的时候就会提示
    示“redefined”。

三、声明与定义的区分:

  一个声明就是一个定义,除非 :
    声明:引入名称
    定义:引入实体

  1. 它声明了一个没有详细说明函数体的函数
  2. 它包含一个extern定义符且没有初始化函数或函数体
  3. 它是一个包含在一个类定义之内的静态类数据成员的声明
  4. 它必须在最终程序的某处准确的定义一次
  5. 它是一个类名声明,如class test;
  6. 它是一个typedef声明。

言外之意:

  • 类的声明也就是定义
  • 同时赋初值的声明也就是定义,如int a=2;
  • 类非静态数据成员的声明也就是定义???
  • 类的所有成员函数的声明也就是定义
    一个定义就是一个声明,除非:
  • 它定义的是一个静态数据成员
  • 它定义了一个非内联成员函数

内部连接和外部连接:

  • 编译时每个文件会被编译成一个含有必要信息的源文件(又叫编译单元),然后编译单元会联结成一个和族文件同名的.o文件,.o文件把不同的编译单元中产生的符号联系起来,构成一个可执行文件。有两种截然不同的链接:内部的和外部的,将这些编译单元联系起来。

内部连接:

  • 对这个定义的访问被局限在当前编译单元,其他编译单元无法访问。

外部连接:

  • 可被其他单元访问,因此名称在整个执行文件中必须唯一。
  • 类的定义(同时也是声明),enum,struct,都是内部连接,内联函数,静态的非类成员数据也是typedef声明的类型也是内联结。
  • 非内联成员函数(包括静态成员)有外部连接,非内联函数,非静态自由函数(非类的成员函数)也是外连接。
  • 声明只对当前编译单元有用,他们不会影响到.o文件,
  • .h文件,由于该文件会被其他.cpp文件包含,但由于声明只是对当前编译单元有效,是不会将符号引入.o文件,所以该文件不能含有任何外部连接的符号(数据成员和函数)的定义。一般情况下也不要包含内连接符号的定义。

综上所诉

.h文件中能包含:

  • 类成员数据的声明,但不能赋值
  • 类静态数据成员的定义和赋值,但不建议,只是个声明就好。
  • 类的成员函数的声明
  • 非类成员函数的声明
  • 常数的定义:如:const int a=5;
  • 静态函数的定义
  • 类的内联函数的定义

不能包含:

  • 所有非静态变量(不是类的数据成员)的声明
  • 默认命名空间声明不要放在头文件,using namespace std;等应放在.cpp中,在.h文件中使用std::string

转载自:link

如何理解C++中的.h文件和.cpp文件相关推荐

  1. .h文件和.cpp文件组织结构

    1.包含关系: .h文件一般包含在.cpp文件中,.h文件中多为变量和类的声明,而.cpp文件才是变量和类中函数的真正定义. 但是#include <iostream> 这个文件既不是.c ...

  2. c语言中.h文件和.cpp文件解析

    理论上来说cpp文件与头文件里的内容,只要是C语言所支持的,无论写什么都可以的,比如你在头文件中写函数体实现,任何一个cpp文件包含此头文件就可以将这个函数编译成目标文件的一部分(编译是以cpp文件为 ...

  3. Qt 生成 ui 对应的 h 文件和 cpp 文件的方法

    2018-04-04 创建人:Ruo_Xiao 开发环境:Qt 5.2.1 邮箱:xclsoftware@163.com 将ui文件copy到uic.exe同一目录下(qt的安装目录中bin下). 打 ...

  4. vs2017/2019中pch.h和pch.cpp是个什么东西(附加,如何删除)

    v s 2017 / 2019 中 p c h . h 和 p c h . c p p 是 个 什 么 东 西 vs2017/2019中pch.h和pch.cpp是个什么东西 vs2017/2019中 ...

  5. Ardunino——面向对象语言学习篇5——.h文件和.cpp文件(制作Arduino类库)

    学习自:太极创客. 实践是检验真理的唯一标准,通过arduino进行实践学习C++或许是一个不错的选择. 前篇回顾   前篇学习了构造函数与析构函数,总体来说就是对象创建和消失时候要执行得函数. 前提 ...

  6. C程序保存为.c文件和.cpp文件的区别

    在学习数据结构时,看到老师把C语言和C++混用,并将文件保存为.cpp类型.关于.c文件和.cpp文件的区别,以下是我的一点看法: 1.首先应该明白,C++是在C语言的基础上拓展而来的,因此C++的语 ...

  7. C++——如何理解.h文件和.cpp文件

    这篇文章是之前摘的笔记放在电脑里,忘记在哪看到的了,就当是原创哈哈哈哈 建立一个以类为名字的XX.h文件,声明类,再建立一个相同名字的XX.cpp文件(要#include "XX.h&quo ...

  8. .c文件与.cpp文件区别

    在编译源文件时,C编译器和C++编译器都会对符号(函数或变量)名作某些修正,但两者采用的修正方法不同,所以两者生成的目标文件不能互相链接.      在C++中使用extern "C&quo ...

  9. Markup.h 和 Markup.cpp 文件(下一篇)内容,直接复制创建就行了

    Markup.h文件 // Markup.h: interface for the CMarkup class. // // Markup Release 11.5 // Copyright (C) ...

  10. C++中头文件(.h)和源文件(.cpp)都应该写些什么

    原文出处:https://www.cnblogs.com/fenghuan/p/4794514.html 头文件(.h): 写类的声明(包括类里面的成员和方法的声明).函数原型.#define常数等, ...

最新文章

  1. BZOJ5102:[POI2018]Prawnicy(贪心,堆)
  2. OpenCV调用TensorFlow预训练模型
  3. 一个95分位延迟要求5ms的场景,如何做性能优化
  4. js for循环_JS 函数的执行时机(深入理解6个6)
  5. 产品经理之深度学习促进产品之分类(三)
  6. HDU2047 阿牛的EOF牛肉串【递推】
  7. 二_单元测试和代码覆盖率
  8. 由儿时的游戏打保猜最广想到的
  9. ios中input输入无效
  10. sqlbulkcopy是覆盖式更新吗_酒店无线覆盖解决方案,一文了解清楚
  11. node2vec python_Node2vec和networkx
  12. OpenCV视频篇——码流 / 码率 / 比特率 / 帧速率 / 分辨率
  13. 记录---提取合并VCF文件
  14. 解决markdown-it-prism未能正确加载Languages的BUG
  15. R语言时间序列分析-根据aic值选择arima模型
  16. Distractor-aware Siamese Networks for Visual Object Tracking 论文学习
  17. Portainer安装配置
  18. php上传 io err,【Dz上传附件】解决Discuz Server(IO)Error问题
  19. 完全理解Unity中PreCompute Realtime GI及其优化(一)
  20. 台湾品牌获得东京威士忌烈酒竞赛2020最佳单一麦芽威士忌总冠军

热门文章

  1. android gradle教程,Android Gradle入门
  2. java 截位法保留小数_资料分析——截位法
  3. Kibana 操作 Elasticsearch
  4. 微信添加好友提示服务器繁忙,微信添加好友提示操作过于频繁怎么办 微信加人频繁的解决方法...
  5. 大数据框架之Spark详解
  6. 高级运维需要掌握哪些技术?
  7. 监控软件加入智能零售 试着用人脸辨识让消费力提升
  8. 在一张图片的某个特定位置添加另外一张图片
  9. win10计算器rsh_win10计算器rsh_如何打开win10计算器 教你打开win10计算器的方法
  10. OV5640摄像头驱动开发讲解