专业移动微网站建设,什么浏览器可以看任何网站,福州网站建设推广平台,有漏洞的网站目录 一.模板实现多个文件分离二.内联为什么不能多个文件分离 前言#xff1a; 对于学习C/C的人#xff0c;会经常接触到一些底层的原理#xff0c;所以除了学习语法以外的知识#xff0c;还需要懂一点有关编译链接过程和涉及到汇编代码的函数栈帧的细节
编译和链接过程 对于学习C/C的人会经常接触到一些底层的原理所以除了学习语法以外的知识还需要懂一点有关编译链接过程和涉及到汇编代码的函数栈帧的细节
编译和链接过程简述 这里有三个文件Test.cpp、Func1.h、Func1.cpp
具体参见 编译和链接详解
为什么会存在多文件这种形式原因有很多 1.有利于模块化管理在实践中一个大型的工程代码量本身是非常大的不可能只将它交给一个人管理会将它进行分模块化再将这些模块一一交给一个组的人员去管理并且编译的时候也可以节省很多时间对自己的模块进行不断修正 2.有利于对代码的可维护性就像我们平时写代码包标准库头文件一样官方库的文档都会介绍是怎么使用的而具体的实现细节是在底层封闭的
常见错误 1.编译过程 2.链接过程
一.模板实现多个文件分离
这里有一个模板用来打印任意结构类型 templateclass Container
void Print(const Container con)
{auto it con.begin();while (it ! con.end()){cout *it ;it;}cout endl;}直接将该模板声明和定义分离成两个文件
//Test.cpp
#define _CRT_SECURE_NO_WARNINGS
#includeFunc1.hint main()
{//Func1();vectorint v{ 1,2,3,4,5,6 };listint li{ 2,3,4,5,6 };Print(v);Print(v1);Print(li);return 0;
}//Func1.h
#pragma once#includeiostream
using namespace std;void Func1();#includevector
#includeListtemplateclass Container
void Print(const Container con);//Func1.cpp
#define _CRT_SECURE_NO_WARNINGS#includeFunc1.hvoid Func1()
{cout void Func1() endl;
}templateclass Container
void Print(const Container con)
{auto it con.begin();while (it ! con.end()){cout *it ;it;}cout endl;}说明链接过程出问题了从编译和链接的过程解析为什么出错 本质上就是实例化的问题从底层的角度头文件压根就不参与该过程并且两个.cpp文件是分别进行处理到链接的过程才进行合并但由于模板需要实例化就导致链接不过
解决方案 1.在.cpp直接显示实例化
//Func1.cpp
templateclass Container
void Print(const Container con)
{auto it con.begin();while (it ! con.end()){cout *it ;it;}cout endl;}//显式实例化
//注意template不能掉
template
void Printvectorint(const vectorint con);template
void Printlistint(const listint con);虽然这种方法解决了当前的问题.cpp不知道实例化什么但是太过于鸡肋如果还有vector仍旧还是有问题的太麻烦了没要使用一次模板就需要实例化所以不推荐
2.模板的声明和定义都放在.h文件中
//Func1.h
//本质编译阶段就确定了指令就不需要在链接阶段再去找对应指令
templateclass Container
void Print(const Container con);templateclass Container
void Print(const Container con)
{auto it con.begin();while (it ! con.end()){cout *it ;it;}cout endl;}将声明和定义都包含在.h文件中Test.cpp文件在编译的阶段就确定了地址就不会在链接阶段寻找地址就不存在找不到对应指令的问题了
这也是标准库里面常用的方法
二.内联为什么不能多个文件分离
分离结果 编译器是报了链接错误说明是call指令找不到的问题
首先我们要认识到函数调用的本质是什么call(一串地址)函数名和数组名类似函数的名字就可以代表函数的地址而去call地址就会进行函数调用 具体参见详解函数栈帧
内联函数和普通函数的区别
内联函数普通函数并不会生成对应的call指令直接展开会生成对应的call指令并在链接的过程进行合并调用
内联函数不生成call指令那么在多文件中进行声明和定义分离.h头文件就会像上面的模板一样找不到对应的指令就不能进行链接了那就只能直接定义在头文件中不做声明和定义分离但是注意内联函数具体是否真正展开取决于编译器的实现并且在类中如果已经确定了函数体很小就可以使用inline修饰如果本身函数体就很大不建议作为内联函数有利于加快编译速度
编译结果 VS下默认是不支持内联函数展开的注意要设置一下