首先,我们可以将所有东西都放在一个.cpp文件内,编译器会将这个.cpp编译成.obj,即编译单元。一个程序可以由一个编译单元组成,也可以由多个编译单元组成。一个.cpp对应一个.obj,然后将所有的.obj链接起来(通过一个叫链接器的程序),组成一个.exe,即程序。如果一个.cpp要用到另一个.cpp定义的函数怎么办,只需在这个.cpp中写上它的函数声明。 链接器将所有的obj链接起来,但是如果碰巧有相同的函数或外部变量怎么办?C++可以通过一种叫做链接属性的关键字来限定,某个函数是属于整个程序公用的,还是只在一个编译单元obj里面使用,这些关键字就是extern(外部链接)和static(内部链接)。让我们说说.h。其实没有.h,程序也能很好的工作,但是当你发现一个外部链接的函数或外部变量,需要许多分声明,因为只要使用到该函数的单元,就必须写一份声明在那个.cpp里面,如果要修改会很麻烦!!!.h就是为了解决这个问题而诞生的,它包含了这些公共的东西,然后所有需要使用该函数的.cpp,只需要用#include包含进去便可,以后需要修改,只是修改一份内容。#include并不是什么申请指令,只是将指定文件的内容,原封不动的拷贝进来。

不是很严格的讲,*.h文件做的是类的声明,包括类成员的定义和函数的声明,而*.cpp文件做的类成员函数的具体实现(定义)。一个*.h文件和*.cpp文件一般是配对的。在*.cpp文件的第一行一般也是#include"*.h"文件,其实也相当于把*.h文件里的东西复制到*.cpp文件的开头。所以,你全部写在*.cpp文件其实也是一样的。

既然可以直接写cpp,为什么还要写hpp?除了编程规范外,还涉及到类一个重要性质,就是封装性。比如现在我们公司和另一家软件公司合作,这样就必然要互相提供一些软件的信息(比如一些类,它到底是要做什么的),可是在提供这些信息的同时我们又不像让对方知道我们这些类的具体实现,毕竟这些是我们公司的算法核心和心血啊。所以这个时候就可以把类的接口(这个类是要做什么的)放在*.h文件中,而具体类的实现放在 *.cpp文件。这时候我们只要给对方公司*.h文件就行了。这样既提供了必要的信息,又保护了我们的核心代码。

1.最表面的机制是:头文件是程序的界面(是代码界面),提供给程序员以  类、模版、函数等一系列的声明,让程序员知道应该怎么调用里面的“东西”。

2.从动态链接库的角度看:头文件提供界面,使得程序员在需要加载一个库函数的时候(这里也仅仅是举简单的例子)查看头文件就知道怎么加载这个动态库内部的函数。

3.从软件的扩展来说:将头文件作为界面,再去定义它的实现,这样只要保证界面不变(头文件不变),就可以只修改实现文件,而不必修改其他的实现代码。比如你有一个sort()函数来排序,在一个大程序中,你后来发现这个sort()有更好的算法,于是你只需要去修改函数的实现(修改.cpp文件的sort()函数的代码),其他使用这个函数的地方可以完全保持不变,这是分割技术的第一个好处

4.从编译的角度看:

所有源文件都是被编译器分别划分单元来分别编译,在编译的过程中,头文件被嵌入到实现文件里面一起作为一个编译单元被编译(实现文件filename.cpp里的#include "filename.h"这一行被替换成filename.h里面的所有内容(实际上会把预处理指令去掉,这才是预处理最本质的作用))。

举一个简单的例子,你定义了sort()函数,在test.h头文件里声明,在test.cpp里定义,这个时候在test.cpp里面#include "test.h",并定义sort()函数。

你需要在头文件内部写预处理代码

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

#ifndef {Filename} 
#define {Filename}

//{Content of head file}   你的代码写在这里

#endif

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

下图是blob.hpp里的前两行可以看到

最后一行:

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

头文件(.h):

  写类的声明(包括类里面的成员和方法的声明)、函数原型、#define常数等,但一般来说不写出具体实现。

  头文件还可以定义:在编译的时候就已知道其值的cosnt对象和inline 函数。在头文件中定义上述实体,是因为编译器需要它们的定义来产生代码。

源文件(.cpp):

  源文件主要写实现头文件中已经声明的那些函数的具体代码。需要注意的是,开头必须#include一下实现的头文件,以及要用到的头文件。那么当你需要用到自己写的头文件中的类时,只需要#include进来就行了。

下面举个最简单的例子来描述一下,咱就求个圆面积。

第1步,建立一个空工程(以在VS2003环境下为例)。

第2步,在头文件的文件夹里新建一个名为Circle.h的头文件,它的内容如下:

#ifndef CIRCLE_H
#define CIRCLE_H

class Circle
{
private:
    double r;//半径
public:
    Circle();//构造函数
    Circle(double R);//构造函数
    double Area();//求面积函数
};

#endif

注意到开头结尾的预编译语句。在头文件里,并不写出函数的具体实现。

第3步,要给出Circle类的具体实现,因此,在源文件夹里新建一个Circle.cpp的文件,它的内容如下:

#include "Circle.h"

Circle::Circle()
{
    this->r=5.0;
}

Circle::Circle(double R)
{
    this->r=R;
}

double Circle:: Area()
{
    return 3.14*r*r;
}

需要注意的是:开头处包含了Circle.h,事实上,只要此cpp文件用到的文件,都要包含进来!这个文件的名字其实不一定要叫Circle.cpp,但非常建议cpp文件与头文件相对应。

最后,我们建一个main.cpp来测试我们写的Circle类,它的内容如下:

#include <iostream>
#include "Circle.h"
using namespace std;

int main()
{
    Circle c(3);
    cout<<"Area="<<c.Area()<<endl;
    return 1;
}

注意到开头时有#include "Circle.h"的声明,证明我们使用到了我们刚才写的Circle类。

至此,我们工程的结构为:

运行一下,输出结果为:

注意这里声明与定义的区别:它们最本质的区别是定义只可以出现一次,声明可以出现多次。声明不分配空间,而定义是要分配空间的。

http://blog.csdn.net/praker/article/details/38231757

https://www.cnblogs.com/fenghuan/p/4794514.html

c++ cpp和hpp的更多相关文章

  1. C++中.cpp和.hpp的区别

    原文地址:https://blog.csdn.net/qzx9059/article/details/89210571 c++中 cpp和hpp我们可以将所有东西都放在一个.cpp文件内,编译器会将这 ...

  2. 《Note --- Unreal --- MemPro (CONTINUE... ...)》

    Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...

  3. faster_rcnn c++版本的 caffe 封装,动态库(2)

    摘要: 转载请注明出处,楼燚(yì)航的blog,http://www.cnblogs.com/louyihang-loves-baiyan/ github上的代码链接,求给星星:) https:// ...

  4. Python实现对文件夹内文本文件递归查找

    平台:Win7 64 bit,IDLE Python 3.4.0 经常有这样的需求:在一个文本文件里查找特定字符串,这很好实现,用任何文本查看工具几乎都可以做到.而有的时候,想查找一个文件夹下的所有文 ...

  5. Makefile.am链接openCV库的写法

    6 INCLUDES = `pkg-config opencv --cflags` -I./ 17 bin_PROGRAMS+=SegRecogServerDeme 18 SegRecogServer ...

  6. [OpenCV] HighGUI

    From: http://www.cnblogs.com/xylc/p/3406026.html 本模块为跨平台的gui/IO组件,支持平台包括windows,linux,mac,IOS,androi ...

  7. Linux: .vimrc

    set nuset autoindentset cindent"set tabstop=2"set shiftwidth=2set cursorlineset hlsearch&q ...

  8. CodeBlocks使用技巧

    快键键 注释:选中后Shfit + C 取消注释:选中后Shfit + X 查找替换:Ctrl + R Build(Ctrl + F9) Run (Ctrl + F10) Build + Run (F ...

  9. cocos2d-js Mac下的JSB绑定步骤

    cocos2d-js由于采用js语言,使得做一些native的功能比较受限,例如文件和目录操作.socket操作等.逼不得已,这时我们就不得不做jsbinding了.. 官方提供的jsbinding方 ...

随机推荐

  1. CMake命令之list

    用途:提供一些列表操作 list(LENGTH <list><output variable>)  list(GET <list> <elementindex ...

  2. RobotFramework:App九宫格滑动解锁

    转自:http://blog.csdn.net/codekxx/article/details/50577381 手势密码在很多手机应用都会运到,手势密码都要求至少连接4个点,但AppiumLibra ...

  3. 1-1 课程导学 & 1-2 项目需求分析,技术分解.

    1-1 课程导学 1-2 项目需求分析,技术分解. 要有一定的dart基础,了解安卓和ios的一些普通的开发

  4. csacademy Round #36(模拟+最坏情况)

    传送门 题意 给出n种袜子,每种袜子个数a[i],两只相同种类袜子配成一对,询问至少拿出多少只袜子能确保配出k对袜子 分析 In order to find out the minimum numbe ...

  5. oauth2(spring security)报错method_not_allowed(Request method 'GET' not supported)解决方法

    报错信息 <MethodNotAllowed> <error>method_not_allowed</error> <error_description> ...

  6. c#数据类型和类型转换

    C# 数据类型 在 C# 中,变量分为以下几种类型: 值类型(Value types) 引用类型(Reference types) 指针类型(Pointer types) 值类型(Value type ...

  7. hdu1811 Rank of Tetris 并查集+拓扑排序

    #include <stdio.h> #include <string.h> #include <vector> #include <queue> us ...

  8. mac 配置nginx 虚拟域名(转载)

    我是通过homebrew 安装nginx 的,所以安装目录是默认的,之前多个server都是放在默认安装目录下的nginx.conf里的,但是这样不太好,就是会导致nginx.conf 越来越长,而且 ...

  9. ulimit资源配置

    基本理解 linux对每个用户能使用的系统资源有一定限制.如果没有限制,在多用户登录,并且都消耗大量资源时,对系统产生复杂的影响.ulimit内建一套参数,来规定一个用户能使用多少资源. [root@ ...

  10. 递推DP HDOJ 5459 Jesus Is Here

    题目传送门 题意:简单来说就是sn = sn-1 + sn-2递推而来,求其中所有c字符的:∑i<j:sn[i..i+2]=sn[j..j+2]=‘‘cff"(j−i) mod 530 ...