c++ 初识模版

目录

1. 函数模板

概念

格式

原理

注意事项(重要)

        1.模版的全缺省

        2.模版不支持分离编译

扩展


void Swap(int& left, int& right)
{
    int temp = left;
    left = right;
    right = temp;
}
void Swap(double& left, double& right)
{
    double temp = left;
    left = right;
    right = temp;
}
void Swap(char& left, char& right)
{
    char temp = left;
    left = right;
    right = temp;
}

         以前,我们如果要实现Swap函数,需要实现三个不同类型参数的函数,我们需要重载很多的同名不同参数类型的重复函数,如上图,会很麻烦,且会使我们的代码变得臃肿。而C++,提供了了函数模版的概念,很好的解决了我们这个问题,这也叫泛型编程。

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础

1. 函数模板

概念

        函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。

格式


        template<typename T1, typename T2,......,typename Tn>
        返回值类型 函数名(参数列表){}

示例如下

//示例
template<typename T>   
void Swap(T a1, T a2)
{
	T tmp = a1;
	a1 = a2;
	a2 = tmp;
}

template<class T>   //typename 和 class 在这里没有区别都可以用
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
    Add(1,2);
    Add(1.1,2.2); //编译可以通过
    return 0;
}

原理

        这其实就相当于让编译器自动去推演我们需要一个怎样的参数函数,把我们该做的丢给编译器去完成。

        当然,我们也可以告诉编译器我们需要一个怎样的参数类型函数,我们称之为显式实例化。

//显式实例化
Add<double>(1,2);//告诉编译器让T类型变成double
Add<int>(1.1,2.2); //告诉编译器让T类型变成int
//示例
template<typename T>   
void Swap(T a1, T a2)
{
	T tmp = a1;
	a1 = a2;
	a2 = tmp;
}

template<class T>   //typename 和 class 在这里没有区别都可以用
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
    Add<double>(1,2);//告诉编译器让T类型变成double
    Add<int>(1.1,2.2); //告诉编译器让T类型变成int
    return 0;
}

输出结果如下图

看上面的代码,我们其实可以提出一个疑问

 ※他们调用的是否是同一个地址的函数?

   并不是,编译器会根据推演参数不同会去自动生成两个函数,跟你自己写是一样的,只不过是丢给编译器去做了。   

让我们进入反汇编来证明。

 我们可以在反汇编很清楚的看到 它们调用了两个不同地址的函数,说明不是同一个函数。

注意事项(重要)

        1.模版的全缺省

        函数的参数可以全缺省,模版的类型也可以进行全缺省,只不过区别是一个是赋值全缺省,一个是类型全缺省。

//示例
template<class T = int>   
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
    Add<>(1,2);  //如果想使用全缺省,就必须要这样写,这其实也是一种显式实例化
    return 0;
}

        2.模版不支持分离编译

        模版不支持分离编译  即 声明和定义不在同一个文件  比如 声明在.h 定义在.cpp 这是不允许的,编译会报错。

       但是可以在同一个文件下声明定义分离,比如在一个.cpp文件下

       其格式非常严格,如下

//示例
template<class T = int>   
T Add(const T& left, const T& right); //声明


template<class T = int>   
T Add<T>(const T& left, const T& right)//定义   格式需要注意这样写
{
	return left + right;
}

int main()
{
    Add<>(1,2);  //如果想使用全缺省,就必须要这样写,这其实也是一种显式实例化
    return 0;
}

扩展

让我们来实现用模版来实现一个栈的结构,可以自己下来先试试。

template<class T = int>   //模版的全缺省格式
class Stack
{
public:
	Stack(size_t capacity = 4)
		:_a(nullptr)
		, _top(0)
		, _capacity(0)
	{
		_a = new T[capacity];
		_capacity = capacity;
	}
	void Push(T x); //声明
	void Pop()
	{
		if (_top > 0)
		{
			--_top;
		}
	}
	~Stack()
	{
		delete[] _a;
		_top = _capacity = 0;
	}
	const T& GetTop()
	{
		assert(_top > 0);
		return _a[_top - 1];
	}
	bool isEmpty()
	{
		return _top == 0;
	}
private:
	T* _a;
	size_t _top;
	size_t _capacity;
};
template<class T>
void Stack<T>::Push(T x)  //类模版类域指定要这样写
{
	if (_top == _capacity)
	{
		_capacity = _capacity == 0 ? 4 : _capacity * 2;
		T* tmp = new T[_capacity];
		if (_a)
		{
			memcpy(tmp, _a, sizeof(T) * _top);
			delete[] _a;
		}
		_a = tmp;
	}
	_a[_top] = x;
	++_top;

}

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

风君子吖

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

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

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

打赏作者

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

抵扣说明:

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

余额充值