C++类模板

泛型编程可以理解为和具体类型无关的编程。

类模板一般没有推演时机,函数模板是实参传递形参,推演函数模板。

类模板一般显示实例化。

 st1和st2是两个不同类型,它俩大小也有可能不同。

比如下面T对于st1和st2分别是double和int,可见两个类的大小是肯定不同的,st1和st2是两种不同的类。

它们是一个类模板实例化出来的,但是模板参数不同,它们就是不同的类型。

下面例子可以证明。

#include <iostream>
#include <assert.h>
using namespace std;
template <typename T>
class Stack
	{

	public:
		Stack(int capacity = 4)
		{
			cout << "Stack(int capacity = )" <<capacity<<endl;
	
			_a = (T*)malloc(sizeof(T)*capacity);
			if (_a == nullptr)
			{
				perror("malloc fail");
				exit(-1);
			}
	
			_top = 0;
			_capacity = capacity;
		}
		Stack(const Stack& s)
		{
			T* news = new T[s._capacity];
			_a = news;
			_top = 0;
			_capacity = s._capacity;
			for (int i = 0;i < s._top;i++)
			{
				_a[_top++] = s._a[i];
			}
		}
		void Swap(Stack& s)
		{
			std::swap(_a, s._a);
			std::swap(_top, s._top);
			std::swap(_capacity, s._capacity);
		}
		Stack& operator = (Stack& s)
		{
			if (this != &s)
			{
				Stack tmp(s);
				Swap(tmp);
			}
			return *this;
		}
		~Stack()
		{
			cout << "~Stack()" << endl;
	
			free(_a);
			_a = nullptr;
			_top = _capacity = 0;
		}
	
		void Push(const T& x)
		{
			// ....
			// 扩容
			_a[_top++] = x;
		}
	
	private:
		T* _a;
		int _top;
		int _capacity;
	};

int main()
{
	Stack<double> st1;
	st1.Push(1.1);
	st1.Push(1.2);
	Stack<int> st2;
	st2.Push(1);
	Stack<double> st3;
	st3.Push(1.1);
	st3 = st1;
	//st1.Push(1.2);
	st3 = st2;
}

 

注意,每个类模板前都要加template<typename T>,不是一个程序只写一个就行。这是对模板的声明。

 再来使用类模板的例子。

#include<iostream>
#include<assert.h>
#define N 10
using namespace std;
template<typename T>
class Array
{
public:
	inline T& operator[](int i)
	{
		assert(i < N);//保证了越界能百分百查找到,普通数组方括号越界是抽查可能会查找不到
		return _a[i];
	}
private:
	T _a[N];
};
int main()
{
	Array<int> a;
	for (int i = 0;i < 10;i++)
	{
		a[i] = i;
	}
	for (int i = 0;i < N;i++)
	{
		cout << a[i] << ' ';
	}
	cout << endl;
	for (int i = 0;i < 10;i++)
	{
		a[i]++ ;
	}
	for (int i = 0;i < N;i++)
	{
		cout << a[i] << ' ';
	}
	cout << endl;

	return 0;
}

 


 

 

 

 模板不支持分离编译,会在链接阶段报错,说明不是语法的问题(缺少;算语法问题 ),而是找不到的问题。

 编译阶段,cpp中Stack和Push要找定义的地址,但此时只有.h,.h中没有定义地址,只有声明地址,但编译阶段编译器会通过,链接时,编译器会找定义的地址,编译器会在Stack.o的符号表里找定义的地址,但却找不到。

把Stack.h中的Push去掉,就没有链接错误,是编译错误,因为编译阶段,Test.cpp没有找到Push的声明或定义,会直接报错。

用的地方实例化了,有实例化的地方的文件只有声明,但此文件没有类的定义,有定义的地方没有实例化,无法生成对应的函数放进符号表里,总之,被调用的模板类及函数不知道T是什么,不能正确被调用。

但有定义的文件中却没有实例化。

第一种 解决方式是在有定义的文件中显示实例化。

template需要加上,需要表明它是个模板。

 但这个方式有一个问题,那就是只要换类型就需要在有定义的文件中再补一个实例化。

第二种解决方式是把定义放入自己写的.h头文件中。因为此时就不需要链接去找,.h头文件中就有这定义,.h已经被.cpp包含,预处理阶段就会展开,此时.cpp文件有声明和定义,声明和定义都被实例化了,就不存在链接的问题。

只有声明没有定义,编译器会在链接时去找定义,造成如上问题,而这里编译时就找到了定义的地址,(而且这个地址是已经实例化后的)。        

inline不会进符号表,但不允许声明和定义分离,这里解决不了问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南种北李

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>