模版分离编译

问题引入

我们创建三个文件,Stack.h Stack.cpp Test.cpp

//Stack.h中存放函数声明
#pragma once
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right);

void func();
//Stack.cpp中存放对函数的实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"

//错解
template<class T>
T Add(const T& left, const T& right) {
	cout << "T Add(const T& left, const T& right)" << endl;
	return left + right;
}

void func() {
	cout << "void func()" << endl;
}
 
//Test.cpp中存放主函数
#include"Stack.h"

#include<iostream>
using namespace std;

int main() {
	Add(1, 2);
	func(); 

	return 0;
}

如果我们编译运行,hui会发现编辑错误,产生无法解析的外部符号。要理解为什么会出错,就需要了解一下编辑器的编译过程。

一、编译器编译过程

Stack.h   Stack.cpp Test.cpp

1、预处理——头文件的展开/宏替换/…

生成文件:Stack.i Test.i

2、编译——检查语法生成汇编代码

函数定义里,会对func生成汇编代码,但不会对Add()生成汇编指令

3、汇编——汇编代码转换二进制机器码

Stack.o Test.o

4、链接

q.out
Add找不到,而func可以找到。Stack.cpp因为Add没有实例化,没有Add的地址,而func可以找到

二、正解

2.1、显示实例化

因为编辑器无法对Add进行实例化,那我们告诉他该怎么实例化就好了。

//正解
//显示实例化
template
int Add<int>(const int& left, const int& right);

添加以上代码到Stack.cpp里,会使编辑器能过正常运行。

可以看到,这里成功调用的Add函数

函数模版的实例化

template<class T>
class Stack
{
public:
	void Push(const T& x);
	void Pop();
private:
	T* _a=nullptr;
	int _top=0;
	int _capacity=0;
};
template<class T>
void Stack(<T>::Push(const T& x)
{
	cout << "void Stack(<T>::Push(const T& x)" << endl;
}
template<class T>
void Pop()
{
	cout << " void Pop()" << endl;
}

template<class T>
void Stack<T>::Pop()
{
	cout << "void Pop()" << endl;
}

template
class Stack<int>;
#include"Stack.h"

#include<iostream>
using namespace std;

int main() {
	/*Add(1, 2);
	func();*/ 

	Stack<int> st;
	st.Push(1);
	st.Pop();
	return 0;
}

运行结果:
可以看到这里我们成功调用了函数模版

但这样我们每次想多用一个模版,就需要专门再实例化一个,岂不是使模版失去了其方便的意义。

可行,但不好用

2.2、将Stack.cpp里的函数实现放在Stack.h中实现,丢弃Stack.cpp。

//更新后的Stack.h,可以看到已经没有实例化了
#pragma once
#include<iostream>
using namespace std;
template<class T>
T Add(const T& left, const T& right);

void func();

template<class T>
class Stack
{
public:
	void Push(const T& x);
	void Pop();
private:
	T* _a=nullptr;
	int _top=0;
	int _capacity=0;
};

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"


template<class T>
T Add(const T& left, const T& right) {
	cout << "T Add(const T& left, const T& right)" << endl;
	return left + right;
}

void func() {
	cout << "void func()" << endl;
}

template<class T>
void Stack<T>::Push(const T& x)
{
	cout << "void Stack(<T>::Push(const T& x)" << endl;
}
template<class T>
void Pop()
{
	cout << " void Pop()" << endl;
}

template<class T>
void Stack<T>::Pop()
{
	cout << "void Pop()" << endl;
}

在这里插入图片描述

为什么声明和定义都放到.h文件后就没问题了?

因为在预处理时,展开头文件,这时头文件里不仅有声明还有定义,编辑器直接找到了类模板的定义,将类模板实例化,确定了地址。

三、模版总结

优点
1、模版复用了代码,节省资源,更快的迭代开发,C++的标准模版库(STL)因此而产生。
2、增强了代码的灵活性
缺点
1、模版会导致代码膨胀问题,也会导致编译时间变长。
2、出现模版编译错误时,错误信息非常凌乱,不易确定错误

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值