泛型编程——模板入门

目录

函数模板 

交换模板 

两数求和

调用顺序问题

类模板

 类模板声明和定义分离


在实现多种类型交换时,我们可以使用引用/指针的方式重载多个类型的函数使其进行交换,但是作为一名合格的程序员,这样做很浪费时间。这篇文章我将讲述模板(template)的入门知识,领略c++的魅力。 

函数模板 

//定义模板
template<class T>
template<typename X>
//多参数
template<class M,class N>

 两种方法都可以定义模板,模板名自取且一般为大写。 

交换模板 

通过调试,每次进入使用了模板的Swap函数体内,并对int和double类型进行交换。

这里存在一个问题,我们调用的是同一个函数吗?

当然不是。

模板之所以称之为模板,是因为它是一个模具,本质还是去分别调用其他重载的函数。每次调用函数就回去推导并实例化对应类型的函数,原理:让编译器干活

题外话:为什么不能用auto?

因为auto只能在编译阶段推导,而函数调用是在运行是阶段确定的,所以不能用auto

反汇编观察:

 c++库里提供了一个swap函数模板,我们以后也可以使用它来进行交换。

两数求和

我们用两数求和实现一个模板来观察一下不同类型求和出现的问题。

template<class X>
X Add(const X& a, const X& b)
{
	return a + b;
}

 可以发现不同类型传参,导致模板的推导存在歧义(如果推导成int类型却识别到另一个类型不为int)存在问题,下面我们提供两种方式来解决。

隐式很好理解,显示写则是通过指明模板所要推导的类型,使其都转化为int类型,注意在这里这两种方式都产生了临时变量,函数需要加const进行修饰。

尽管都能解决问题,不过注意尽量不要不同类型进行加运算,以免发生精度丢失等问题。

调用顺序问题

有这样一种场景,如果我们写好了一种类型的加法函数和它的模板,编译器会去调用哪个的问题。

显式调用模板操作:

Add<int>(a, b);//<int,int>调用单参
Add<int>(a,c);//<int,double>调用双参,无双参模板报错
Add<int>(c,a);//c强转为int,<int,int>调用单参
Add<int,double>(a,b);//显式调用双参
Add<int,int>(a,b);//显式调双参

模板支持重载 

 可以看到编译器很聪明,我们写好的int类型的加法会优先调用,这样可以不用再实例化对应的函数了,第二次编译器再两个模板中选择了第二个,这又说明了编译器会调用最匹配的一个模板。

类模板

好比我们要实现一个栈,我用typedef定义一个内部存储int类型的栈,那之后我们每一个对象都只能存int类型,无法做到存double类型,要是再创建一个类又要自己实现大量重复代码,这肯定是不行的。为此,用模板写类很有必要。

重写栈类:

template <class M>
class Vector
{
public:
	Vector(int capaicty = 4)
	{
		_a = new M[capaicty];//
		_top = 0;
		_capacity = capaicty;
	}
	M& operator[](int pos)
	{
		assert(pos < _top);
		return _a[pos];
	}
    void pushback(const M& x);
	~Vector()
	{
		delete[] _a;//开辟的是数组空间
        _a = nullptr;
		_capacity = _top = 0;
	}

private:
	M* _a;//
	size_t _top;
	size_t _capacity;
};

 编译器生成不同类型栈

Vector <int> s1;
Vector <double> s2;

与函数模板不同,类模板实例化需要在后面加上<>,括号里为数据类型,编译器根据相应类型调用不同的类,以此构成一个完整的类类型。(普通类的类名是类名+类型)这里的Vector是我们自己取得类模板名字。

 类模板声明和定义分离

注意类模板的声明和定义分离有点不一样,它们只能放在同一个文件里,否则会发生链接错误

我们以~Vector为例来看:

~Vector();//声明
template <class M>//定义
Vector<M>:: ~Vector()
{
	delete[] _a;
	_a = nullptr;
	_capacity = _top = 0;
}

 这里要注意定义要在第一行跟上模板的定义且Vector后要加上<M>构成完整类型,一般不推荐将声明和定义分离。

这就是模板初阶的基本内容了,之后我们还会谈进阶模板,不要忘了一键三连啊! 

猜你喜欢

转载自blog.csdn.net/dwededewde/article/details/130783624