C++中有的东西需要放在可以在.h文件中定义,有的东西则必须放在.cpp文件中定义,有的东西在不同的cpp文件中的名字可以一样,而有的则不能一样

那么究竟哪些东西可在头文件中定义,声明,哪些东西又必须在.cpp中定义,声明呢?

*以下所有的讨论都是在全局命名空间中(即不定义自己的namespace)下进行的

函数

1、在.h中只能声明函数,在.cpp中可以声明与定义函数

如果在.h中声明并定义一个函数,则该函数只能被#include一次,否则则会出现重定义错误

比如

1.h

#pragma once

void show()
{ }

a.cpp

#include "1.h"

b.cpp

#include "1.h"

error LNK2005: "void __cdecl show(void)" (?show@@YAXXZ) 已经在 a.obj 中定义

所以要避免在头文件中定义函数

2、在不同.cpp中定义的函数原型(函数返回值,函数名称,函数参数)不能完全一样,

比如如果有在两个.cpp文件中均存在

void show(){};

会出现重定义错误

内联函数

为了确保所有调用该inline函数的文件中的定义一样,所以需要是在.h文件中定义

注意这里的inline对于编译器来说只是建议性的,关于该内联函数被拒绝会在下一篇文章中介绍

typedef

在不同的cpp中可以一样

变量

1、在.h中只能声明,在.cpp中可以声明与定义一个变量

如果在.h中的定义一个变量,则该变量被include两次以上时则会出现重定义错误

2、在不同.cpp中定义的变量的名字与类型不同一样

常量

1、如果const常量是用常量表达式进行初始化的,则可以在.h中声明与定义

2、如果const变量是用非常量表达式进行初始化的,那么该变量应该在cpp文件中定义,而在.h文件中进行声明。

3、不同cpp中以定义名字与类型一样的变量

static变量

1、在不同的cpp中可以定义名字与类型一样的变量

2、如果在.h中定义一个static成员,则所有include该文件的文件均拥有一份独立的该static成员,一个文件对其的修改不会影响到另一个文件

所以static变量一般是放在.cpp出现并定义.

例如

1.h

#pragma once

static int a = ;

a.cpp

#include "1.h"
#include <iostream>
using namespace std; void showstatic()
{
cout << "In a.cpp:" << a << endl;
a = ;
cout << "In a.cpp:" << a << endl;
}

b.cpp

#include "1.h"
#include <iostream>
using namespace std; void showstatic();
int main()
{
showstatic();
cout << "In b.cpp:" << a << endl;
system("pause");
}

static函数

在不同的cpp中可以定义函数原型一样的函数

不同的cpp中类的名字可以一样

类成员与函数

在.h中定义,所有成员必须在类中声明,在cpp中实现

非静态的常量整形数据成员不能就地初始化(*C++11中,标准允许使用等号=或者花括号{}进行就地的非静态成员变量初始化)

在类内部定义的成员函数将自动作为inline处理

在.h外部定义的函数需要加上inline说明

否则在被include多次时会出现重定义错误

1.h

#pragma once
#include <iostream> class A
{
public:
void show();
};
void A::show()//无inline
{
std::cout << "hello" << std::endl;
}

a.cpp

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

b.cpp

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

error LNK2005: "public: void __thiscall A::show(void)" (?show@A@@QAEXXZ) 已经在 a.obj 中定义

类的const成员

在类中声明变量为const类型的成员不可以就地初始化

const常量的初始化必须在构造函数初始化列表中初始化,而不可以在构造函数函数体内初始化(*C++11中,标准允许使用等号=或者花括号{}进行就地的非静态成员变量初始化)

#pragma once
class A
{
public:
const int i=;
};

error C2864: “A::i”: 只有静态常量整型数据成员才可以在类中初始化    d:\我的资料库\documents\visual studio 2010\projects\fasd\fasd\1.h    5    1    fasd

类的静态的数据成员

不可以就地初始化,需要到.cpp中进行定义

(对于非常量的静态成员变量,C++11与C++98保持了一致。需要到头文件以外去定义它)

类的静态的常量整形数据成员

可以就地初始化

class A
{
private:
const static int i = ;
};

模板(不考虑export)

模板函数与模板类的声明与实现必须放在一个文件中

总结

  是否可以在.h中定义 在不同.cpp中是否可以重名 特殊说明
函数 不可以,会出现重定义错误 不可以  
内联函数 可以 可以 为了确保所有调用该inline函数的文件中的定义一样,所以需要是在.h文件中定义
typedef ---------------------- 可以  
常量 可以 可以

1、常量表达式进行初始化的,则可以在.h中声明与定义

2、非常量表达式进行初始化的,那么该变量应该在cpp文件中定义,而在.h文件中进行声明。

变量 不可以,会出现重定义错误 不可以(类型与名字)  
static变量 可以 可以

在.h中定义一个static成员,则所有include该文件的文件均拥有一份独立的该static成员,一个文件对其的修改不会影响到另一个文件

所以static变量一般是放在.cpp出现并定义.

static函数 可以 可以  
  是否可以在.h中定义 是否可以就地初始化 特殊说明
可以    
类数据成员 ------------------ 不可以 (*C++11中,标准允许使用等号=或者花括号{}进行就地的非静态成员变量初始化)
类成员函数 ------------------ ----------------

在.h外部定义的函数需要加上inline说明

否则在被include多次时会出现重定义错误

类const数据 ------------------ 不可以

1、在类中声明变量为const类型的成员不可以就地初始化

const常量的初始化必须在构造函数初始化列表中初始化,而不可以在构造函数函数体内初始化

2、同类数据成员中的特殊说明

类的静态的数据成员 ------------------- 不可以

不可以就地初始化,需要到.cpp中进行定义

(对于非常量的静态成员变量,C++11与C++98保持了一致。需要到头文件以外去定义它)

类的静态的常量整形数据成员

------------------ 可以  
  特殊说明
模板

模板函数与模板类的声明与实现必须放在一个文件中

至于为什么会这样,与C++的编译和链接,和编译产生的目标文件(.obj),内部链接,外部链接有关,

我会在接下来的文章中向大家介绍

C++编译与链接(0)-.h与.cpp中的定义与声明的更多相关文章

  1. template 不能分别在.h和.cpp中定义模板

    先上代码: #ifndef SEQLIST_H #define SEQLIST_H #include <iostream> ; template <typename type> ...

  2. 窥探C语言程序的编译、链接与.h文件

    概述 C语言程序从源文件经过编译.链接生成可执行文件.那么编译与链接分别做了什么? 开发中为什么使用.h编写函数的声明?接下来使用案例说清楚为什么这样编写代码. C语言程序的编译和链接 C语言程序从源 ...

  3. 在.h和.cpp中包含头文件的区别

    1.在.h中包含头文件,是为了声明一系列这个头文件的变量等,可能会产生重复包含的问题: 2.在.cpp中包含头文件只是为了实现这个头文件或者使用其中的方法,不会有重复包含的问题,所以尽量在源文件中包含 ...

  4. 在 .h 和 cpp 中查找 :grep consume ~/test/2016/AMQP-CPP/**/*.cpp ~/test/2016/AMQP-CPP/**/*.h -r

    :grep consume ~/test/2016/AMQP-CPP/**/*.cpp ~/test/2016/AMQP-CPP/**/*.h -r -w "whole" 匹配整个 ...

  5. 原创 C++应用程序在Windows下的编译、链接:第三部分 静态链接(二)

    3.5.2动态链接库的创建 3.5.2.1动态链接库的创建流程 动态链接库的创建流程如下图所示: 在系统设计阶段,主要的设计内容包括:类结构的设计以及功能类之间的关系,动态链接库的接口.在动态链接库中 ...

  6. C++编译与链接(2)-浅谈内部链接与外部链接

    发现每次写技术博客时,都会在文章开头处花费一番功夫 ...从前,有一个程序员....他的名字叫magicsoar 为什么有时会出现aaa已在bbb中重定义的错误? 为什么有时会出现无法解析的外部符号? ...

  7. C++模板声明与实现分开--由此想到的编译,链接原理

    参考了以下两篇文章: C++编译链接原理简介  语言程序编译过程 2 问题来源:当模板文件的实现与声明分开在不同文件中时,链接时会提示找不到相应模板函数,如下 一,编译和链接的大概原理: 1,编译,遍 ...

  8. c++ *.h和*.cpp在编译中的作用

    首先,我们可以将所有东西都放在一个.cpp文件内.然后编译器就将这个.cpp编译成.obj,obj是什么东西?就是编译单元了. 一个程序,可以由一个编译单元组成,也可以有多个编译单元组成. 如果你不想 ...

  9. 原创 C++应用程序在Windows下的编译、链接:第一部分 概述

    本文是对C++应用程序在Windows下的编译.链接的深入理解和分析,文章的目录如下: 我们先看第一章概述部分. 1概述 1.1编译工具简介 cl.exe是windows平台下的编译器,link.ex ...

随机推荐

  1. Gson转换复杂对象报错【类型强转错误】

    一.问题: 项目里遇到一个需求,规则文件下载后,导入本地解析. 采用的方案是:获取复杂对象,使用谷歌Gson转换为字串保存为文件下载,客户端读取文件,解析字串,反解对象 遇到的问题:传输的对象是一个嵌 ...

  2. Linux下开发python django程序(Form表单对象创建和使用)

    1.在setting.py文件中修改节点,注释掉其中一行 MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'dj ...

  3. MongoDB操作-备份和恢复,导入和导出

    mongodb数据备份和恢复主要分为二种:一种是针对库的mongodump和mongorestore,一种是针对库中表的mongoexport和mongoimport 1. 常用命令格式 mongod ...

  4. [BZOJ4475][JSOI2015]子集选取[推导]

    题意 题目链接 分析 显然可以看成一个位数为 \(n\) 的二进制数然后每一位分开考虑然后求和.最后的答案是 \(w^n\) 的形式. 考虑一个dp. 定义状态 \(f_{i}\) 表示选择了长度为 ...

  5. 网络编程的演进——从Apache到Nginx

    Apache 1.Apache HTTP服务器是 Robert McCool 在1995年写成,并在1999年开始在Apache软件基金会的 框架下进行开发. 由于Apache HTTP服务器是基金会 ...

  6. Tomcat性能优化方案

    1. 提高JVM栈内存Increase JVM heap memory 你使用过tomcat的话,简单的说就是"内存溢出". 通常情况下,这种问题出现在实际的生产环境中.产生这种问 ...

  7. Unity 自定义编辑器窗口 画线

    最近在学习状态机, 想自己实现一个可视化编辑器, 需要将多个状态之间用线条连接起来, 效果如下: 代码如下: Material m;Vector2 start;Vector2 end;Color co ...

  8. python3安装与环境配置和pip的基本使用

    本文环境 系统: Windows10 Python版本: 3.6 安装 python安装包下载 可以选择安装版和解压版 安装版一键安装, 安装过程注意选择安装位置, xx To Path选项(勾选), ...

  9. Python实现学生系统

    # 4. 修改之前的学生信息管理程序,实现添加菜单和选择菜单操作功能: # 菜单: # +-----------------------------+ # | 1) 添加学生信息 | # | 2) 查 ...

  10. Tensorflow张量的形状表示方法

    对输入或输出而言: 一个张量的形状为a x b x c x d,实际写出这个张量时: 最外层括号[…]表示这个是一个张量,无别的意义! 次外层括号有a个,表示这个张量里有a个样本 再往内的括号有b个, ...