C++ 对函数模版和类模版的理解

所谓模板,实际上是建立一个通用函数或类,其类内部的类型和函数的形参类型不具体指定,用一个虚拟的类型来代表。


就比方说你想要实现 一个Add的加法函数,面对不同的类型,你是否要进行多次函数重载呢,其实这多个函数实现的底层原理都是一样的,只不过是类型不同,所以祖师爷就根据这种情况设计出了模版。

f92327ff0540447da917b336a1fb68b5.jpeg


 函数模版

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


格式要求

在定义函数前要写上这一行:template<typename T1, typename T2,......,typename Tn>,这里的typename换成class也是OK的。而函数定义就是正常写,只不过将原来的实例化类型换成虚拟化类型(也就是上一行的T1、T2......)


举例Add函数模版

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

因为这里需要整体替换的就一个类型所以模版形参中给一个T就行。

但是你的类型也必须要进行统一才可以:

int main()
{
	double sum = Add(1.2, 1);
	cout << sum << endl;
}

如果主函数这样写的话,那就会报错:  没有与参数列表匹配的 函数模板 "Add"

这样也有有解决方法:函数模版实例化(实际也是类型匹配)


函数模版实例化 

函数模版的实例化其实也就是将函数参数进行统一成其中一个实例化模版函数的参数。

隐式实例化

即是不直接告诉编译器参数的类型,让编译器在自己生成的模拟板函数中去找与之匹配的。

template<class T>
T Add(const T& a, const T& b)
{
	return a + b;
}
int main()
{
	double sum = Add(1.2, (double)1);//强制类型转换
	cout << sum << endl;
}

其实这就是一种隐式转换。

其实在你写模版函数时发生了两次编译:

  1. 实例化前,先检查模板代码本身,查看语法是否正确。
  2. 实例化期间,检查模板代码,查看是否所有的调用都有效。

在函数模版生成时就相当于编译器自己生成了多个不同类型的重载函数,在你调用函数模版时,编译器就会在生成的所有重载函数中找一个最匹配的让你调用。

显式实例化 

显示实例化的特点就是在函数名后面加 <type>,type就是你调用函数时的具体类型

int main()
{
	double sum = Add<double>(1.2,1);
	cout << sum << endl;
}

这就相当于直接告诉编译器调用的函数参数类型是double型,所以这就是显式实例化 。

类模版

类模版其实和上面讲到的函数模版使用起来几乎一样

template<typename T, int N>
class Test
{
public:
    Test()
        :_arr(new T[N])
    {
        for (int i = 0; i < N; i++)
            _arr[i] = i+0.5;
    }
    ~Test()
    {
        delete[]_arr;
    }

private:
    T* _arr;
};

像这个模版的功能就是单纯的创建一个数组并完成初始化,这里用到了两个模版参数,所以就写成:template<typename T, int N>,int N是数组大小,所以就直接写int类型就行,N才是其中的一个参数。

但是类模版相较于函数模版没有隐式实例化,只能通过显式实例化来创建对象。

int main()
{
    Test<double,5> arr;
}

因为你如果不显式实例化调用的话,编译器自己是识别不出来具体的模版函数的。


类模板中函数放在类外进行定义时,需要加上模板参数列表

template<typename T, int N>
class Test
{
public:
    Test();
    ~Test()
    {
        delete[]_arr;
    }

private:
    T* _arr;
};

template<typename T, int N>
Test<T, N>::Test()
:_arr(new T[N])
{
    for (int i = 0; i < N; i++)
        _arr[i] = i + 0.5;
}

不仅仅要加上模版参数列表,还要加上类类型,模版类的类型和一般类的类型是不一样的,模版类的类型=类名+<T1,T2...>,而相较于一般的类而言,类名就是类型

模版类和类模版的概念

模板类(Template Class)和类模板(Class Template)是同一概念的不同表述。


模板类(Template Class)是指使用模板定义的、具有泛型特性的类。通过定义模板类,可以实现类的通用性,使其能够适用于不同的数据类型。例如,可以使用模板类来定义一个通用的链表类,使其能够存储不同类型的数据。

类模板(Class Template)是指定义类的模板,其中将一个或多个类型作为参数,这些参数可以在创建类的对象时指定具体的类型。类模板可以看作是一个创建自定义类的蓝图,创建对象时可以根据需要为模板参数指定不同的类型。例如,可以定义一个通用的容器类模板,其中的元素类型可以根据实际需求而改变。

因此,模板类和类模板本质上是同一概念,只是表述上稍有不同。模板类强调的是使用模板来定义类的特点,而类模板强调的是定义类的模板本身。

模版的参数

现在谈一谈模版的参数,提前声明:模版参数可不是函数参数和类参数,这一定要分开。

模版参数的形参就是模板参数列表中的T,用上面的模版类为例就是有两个模版参数T和N而有了形参,实参也就容易了,就是double和5.



欢迎莅临指导!!!

203bdc7adca845edb657314c2a177355.jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

CR0712

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

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

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

打赏作者

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

抵扣说明:

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

余额充值