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 ...
随机推荐
- Kubernetes学习之路(十二)之Pod控制器--ReplicaSet、Deployment
一.Pod控制器及其功用 Pod控制器是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试 进行重启,当根据重启策略无效,则会重新新建pod的资源. pod控制器 ...
- Linux新手常见问题
yum与apt的区别 参考:https://blog.csdn.net/qq_26182553/article/details/79869666 ubuntu下su: Authentication f ...
- pymysql模块使用教程
一.操作数据库模板 pymysql是Python中操作mysql的模块,(使用方法几乎和MySQLdb相同,但是在Python3中,mysqldb这个库已经不能继续使用了) 下载安装方法: 方法一. ...
- Java的自动拆/装箱
作者:Alvin 关键字:语法糖 类 对象 参考 Java 中的语法糖 语法糖--这一篇全了解 浅谈 Integer 类 什么是Java中的自动拆装箱 深入剖析Java中的装箱和拆箱 前言 我们知道, ...
- python 模块之 bisect
python一个有趣的模块,bisect,感觉挺有趣,怎么有趣呢,下面来给你道来. 我们先生成一个list data=[4,8,7,1] data.sort() 打印这个list [1,4,7,8] ...
- JUC——线程同步锁(ReentrantReadWriteLock读写锁)
读写锁简介 所谓的读写锁值得是两把锁,在进行数据写入的时候有一个把“写锁”,而在进行数据读取的时候有一把“读锁”. 写锁会实现线程安全同步处理操作,而读锁可以被多个对象读取获取. 读写锁:ReadWr ...
- WebGL实现sprite精灵效果的GUI控件
threejs已经有了sprite插件,这就方便了three的用户,直接可以使用threejs的sprite插件来制作GUI模型.sprite插件是阿里的lasoy老师改造过的,这个很厉害,要学习一哈 ...
- Java 的JAR包、EAR包、WAR包区别
一.WAR包 WAR(Web Archive file) 网络应用程序文件,是与平台无关的文件格式,它允许将许多文件组合成一个压缩文件.WAR专用于Web方面.大部分的JAVA WEB工程,都是打成W ...
- InsertionSort 直接插入排序(java)
排序思想: 相当于一堆数字,一开始先取出2个数排序,2个数排好序之后,再从一堆数字里面取一个数排序,直到结束伪代码: INSERTION_SORT(A) for j = 2 to A.length k ...
- CDN的基本原理和基础架构
CDN基本原理 最简单的CDN网络由一个DNS服务器和几台缓存服务器组成: ①当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DN ...