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 ...
随机推荐
- 《Java 程序设计》课堂实践项目-类定义
<Java 程序设计>课堂实践项目类定义 课后学习总结 目录 改变 类定义实验要求 课堂实践成果 课后思考 改变 修改了博客整体布局,过去就贴个代码贴个图很草率,这次布局和内容都有修改. ...
- 13-[函数进阶]-列表生成式,生成器&迭代器
1.列表生成式 Python一种独特的语法,相当于语法糖的存在,可以帮你在某些场合写出比较精简酷炫的代码.但没有它,也不会有太多的影响. 语法糖(Syntactic sugar),也译为糖衣语法,是由 ...
- 6-[多线程]-互斥锁、GIL、死锁、递归锁、信号量
1.互斥锁(排他锁) (1)不加锁的情况下 并发控制问题:多个事务并发执行,可能产生操作冲突,出现下面的3种情况 丢失修改错误 不能重复读错误 读脏数据错误 # mutex from threadin ...
- SpringCloud-初识微服务(一)
前言 本篇文章简单介绍一下什么是微服务.微服务的优点.SpringCloud的微服务架构核心组件选型等: 一.什么是微服务? 微服务的提出者Martin Fowler是这样描述微服务的(原文:http ...
- Python_sklearn机器学习库学习笔记(七)the perceptron(感知器)
一.感知器 感知器是Frank Rosenblatt在1957年就职于Cornell航空实验室时发明的,其灵感来自于对人脑的仿真,大脑是处理信息的神经元(neurons)细胞和链接神经元细胞进行信息传 ...
- HDU - 5877 Weak Pair (dfs+树状数组)
题目链接:Weak Pair 题意: 给出一颗有根树,如果有一对u,v,如果满足u是v的父节点且vec[u]×vec[v]<=k,则称这对结点是虚弱的,问这棵树中有几对虚弱的结点. 题解: 刚开 ...
- java 迭代器只遍历了一次的解决方案
/** * 注意:因为迭代器只能遍历一次 所以每次用完都要重新填充一次 否则会出现只替换了一次检查配置项的情况 * templateJsonIterator = templateJsonObject. ...
- flask之URL和视图(一)
1.Flask URL和视图 1.1.第一个flask程序 from flask import Flask #创建一个Flask对象,传递__name__参数进去 app = Flask(__name ...
- MYSQL创建表的约束条件(可选)
一.常用的一些约束条件 一.创建表的完整语法1.创建表的万能模板:create table 库名.表名( 字段名1 类型[(宽度) 约束条件], 字段名2 类型[(宽度) 约束条件], 字段名3 类型 ...
- Python 学习 第五篇:语句和语法
Python程序是语句构成的,语句包含表达式,表达式嵌套在语句中,包含变量和常量,用于处理对象.Python的语法实质上是由表达式.语句和代码块构成的.语句是由表达式构成的,代码块是由多个语句构成的复 ...