C++编译与链接(0)-.h与.cpp中的定义与声明
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中的定义与声明的更多相关文章
- template 不能分别在.h和.cpp中定义模板
先上代码: #ifndef SEQLIST_H #define SEQLIST_H #include <iostream> ; template <typename type> ...
- 窥探C语言程序的编译、链接与.h文件
概述 C语言程序从源文件经过编译.链接生成可执行文件.那么编译与链接分别做了什么? 开发中为什么使用.h编写函数的声明?接下来使用案例说清楚为什么这样编写代码. C语言程序的编译和链接 C语言程序从源 ...
- 在.h和.cpp中包含头文件的区别
1.在.h中包含头文件,是为了声明一系列这个头文件的变量等,可能会产生重复包含的问题: 2.在.cpp中包含头文件只是为了实现这个头文件或者使用其中的方法,不会有重复包含的问题,所以尽量在源文件中包含 ...
- 在 .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" 匹配整个 ...
- 原创 C++应用程序在Windows下的编译、链接:第三部分 静态链接(二)
3.5.2动态链接库的创建 3.5.2.1动态链接库的创建流程 动态链接库的创建流程如下图所示: 在系统设计阶段,主要的设计内容包括:类结构的设计以及功能类之间的关系,动态链接库的接口.在动态链接库中 ...
- C++编译与链接(2)-浅谈内部链接与外部链接
发现每次写技术博客时,都会在文章开头处花费一番功夫 ...从前,有一个程序员....他的名字叫magicsoar 为什么有时会出现aaa已在bbb中重定义的错误? 为什么有时会出现无法解析的外部符号? ...
- C++模板声明与实现分开--由此想到的编译,链接原理
参考了以下两篇文章: C++编译链接原理简介 语言程序编译过程 2 问题来源:当模板文件的实现与声明分开在不同文件中时,链接时会提示找不到相应模板函数,如下 一,编译和链接的大概原理: 1,编译,遍 ...
- c++ *.h和*.cpp在编译中的作用
首先,我们可以将所有东西都放在一个.cpp文件内.然后编译器就将这个.cpp编译成.obj,obj是什么东西?就是编译单元了. 一个程序,可以由一个编译单元组成,也可以有多个编译单元组成. 如果你不想 ...
- 原创 C++应用程序在Windows下的编译、链接:第一部分 概述
本文是对C++应用程序在Windows下的编译.链接的深入理解和分析,文章的目录如下: 我们先看第一章概述部分. 1概述 1.1编译工具简介 cl.exe是windows平台下的编译器,link.ex ...
随机推荐
- C++引用的用处
原文:http://www.cnblogs.com/ddx-deng/archive/2012/12/16/3755864.html 一.什么是“引用”?声明和使用“引用”要注意哪些问题? 答:引用就 ...
- 20155321 《信息安全系统设计》课堂测试(ch06)
20155321 <信息安全系统设计>课堂测试(ch06) (单选题|1分)下面代码中,对数组x填充后,采用直接映射高速缓存,所有对x和y引用的命中率为() A .1 B .1/4 C . ...
- 20155327Exp2 后门原理与实践
20155327Exp2 后门原理与实践 一.实验说明 任务一:使用netcat获取主机操作Shell,cron启动 (0.5分) 任务二:使用socat获取主机操作Shell, 任务计划启动 (0. ...
- import require
https://www.zhihu.com/question/56820346/answer/150743994
- re 模块错误 error: bad character range
下午,看到堆栈的内容.于是上机实验了一番 >>> bds = '10+6/5-4*2' # 数学运算表达式 想用 findall 把运算符号提取出来 >>> imp ...
- Codeforces 469 D. Two Sets (并查集)
题目链接:Two Sets 题意: 有n个数,要分成A.B两组,要求如果x∈A则a-x∈A,如果x∈B则b-x∈B,问是否存在一种符合要求的分法. 题解: 并查集,先增加两个点表示A和B集合的根,对于 ...
- NGUI可展开列表的实现
本文来自网易云社区 作者:汪毅军 最近使用了NGUI做了下可展开列表,其主要思路如下:首先最外层使用Scroll view以达到滑动效果,然后列表使用UITable进行排列,最后通过点击Item控制I ...
- 通过Task异步加快对数组的运算
一.介绍 Task是.NetFramework3.0出现的,线程是基于线程池,然后提供了丰富的API. 先用AverageAssign方法把一组数据平均分成n组,再通过遍历n组数据,循环开Task多线 ...
- Python3列表中获取相同元素出现位置的下标
前言 list: Python3的列表类型, 和其他语言中的数组类似 定义格式: l = ["a", "b", "c", "a&q ...
- 基础:enctype 包含上传input时必须(解决图片上传不成功问题)
今天在做一个上传图片的时候,死活就是看不到传过去的值..对比了写法没发现问题,后来抱着试试看的心,查看下了 from里的写法.发现缺少了enctype.不了解这个用法,特意百度了下. enctype ...