您当前的位置: 首页 >  c++

风间琉璃•

暂无认证

  • 6浏览

    0关注

    337博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

C++ 模板

风间琉璃• 发布时间:2022-10-17 23:28:08 ,浏览量:6

  • 💂 个人主页:风间琉璃
  • 🤟 版权: 本文由【风间琉璃】原创、在CSDN首发、需要转载请联系博主
  • 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦

目录

目录

一、模板的引出

二、函数模板

1.函数模板语法

2.函数模板原理

3.函数模板实例化(调用)

①显示实例化

②隐式实例化

4.函数模板的匹配原则

三、类模板

        1.类模板语法

        2.类模板原理

        3.类模板的实例化(调用)

四、模板的特化

1.函数模板特化

2.类模板的特化

①全特化

②类模板的成员特化

③局部特化

五、模板参数

1.模板参数的默认值

2.类模板的非类型参数

3.模板的模板参数

六、模板成员

七、类模板的继承

1.类继承类模板

2.类模板继承类

3.类模板继承类模板

4.继承中使用模板参数

八、模板的递归实例化

九、模板的划分

在这里插入图片描述

一、模板的引出

在C++中,函数重载使得用于交换不同类型变量的函数可以拥有相同的函数名,并且传参使用引用传参。但是,这种代码仍然存在它的不足之处:

①重载的多个函数仅仅只是类型不同,代码的复用率比较低,只要出现新的类型需要交换,就需要新增对应的重载函数。

②代码的可维护性比较低,其中一个重载函数出现错误可能意味着所有的重载函数都出现了错误。

C++引入模板,建立通用的模具,提升了代码的复用性,实现类型通用,降低代码的冗余度。模板可以为一种算法定义不同类型的版本。

实现机制:

①使用类型参数突破类型的限制,丧失一定的类型安全

②模板需要实例化才能使用,实例化由编译器完成

模板特点:模板不可以直接使用,它只是一个框架。模板的通用性不是万能的。

模板一般分为函数模板和类模板。

 二、函数模板

函数模板是带类型参数的函数,函数的返回值,形参,局部变量都可以使用类型参数,函数模板支持类型推断(形参)。

1.函数模板语法

建立一个通用的函数,其返回类型和参数类型可以不指定,可以通过一个虚拟的类型来替代。

语法:

//函数模板的声明
template
返回值类型 函数模板名(形参列表)
{
    .......//可以使用T作为类型
}

template :是用来定义模板类型的关键字,也可以用class(不能用struct代替

typename :后面的字符表示为一个数据类型,可以被class替换

T :通用数据类型,可以被替换,但一般使用大写字母

template
void Swap(T& x, T& y)
{
	T tmp = x;
	x = y;
	y = tmp;
}

2.函数模板原理

函数模板是一个蓝图,它本身并不是函数。是编译器产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器。

在编译器编译阶段,对于函数模板的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。

比如,当用int类型使用函数模板时,编译器通过对实参类型的推演,将T确定为int类型,然后产生一份处理int类型的代码,对于double类型也是如此。 

3.函数模板实例化(调用)

用不同类型的参数使用模板时,称为模板的实例化。模板实例化分为隐式实例化和显示实例化。

①显示实例化

显示实例化:在函数名后的中指定模板参数的实际类型

template
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10;
	double b = 1.1;
	int c = Add(a, b); //指定模板参数的实际类型为int
	return 0;
}

使用显示实例化时,如果传入的参数类型与模板参数类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功,则编译器将会报错。

②隐式实例化

隐式实例化:让编译器根据实参推演模板参数的实际类型。只有函数模板支持类型推断。

template
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10, b = 20;
	int c = Add(a, b);   //编译器根据实参a和b推演出模板参数为int类型
	return 0;
}

当推导方式为自动推导时,推导的类型必须是同一个类型才可以使用。 当传入两个不同数据类型的值,编译器则分辨不出T应该表示哪种数据类型,因此要避免写出这样的代码。否则只要使用①的方式不仅要传入模板参数类型还要传入形参。

函数模板的调用:

函数模板名(实参); 

如果函数模板的类型参数可以通过实参来判断,传递的类型可以省略。

4.函数模板的匹配原则

①一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数。

//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{
	return x + y;
}
//通用类型加法的函数模板
template
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = 10, b = 20;
	int c = Add(a, b); //调用非模板函数,编译器不需要实例化
	int d = Add(a, b); //调用编译器实例化的Add函数
	return 0;
}

②对于非模板函数和同名的函数模板,如果其他条件都相同,在调用时会优先调用非模板函数,而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么选择模板。

//专门用于int类型加法的非模板函数
int Add(const int& x, const int& y)
{
	return x + y;
}
//通用类型加法的函数模板
template
T1 Add(const T1& x, const T2& y)
{
	return x + y;
}
int main()
{
	int a = Add(10, 20); //与非模板函数完全匹配,不需要函数模板实例化
	int b = Add(2.2, 2); //函数模板可以生成更加匹配的版本,编译器会根据实参生成更加匹配的Add函数
	return 0;
}

③模板函数不允许自动类型转换,但普通函数可以进行自动类型转换

template
T Add(const T& x, const T& y)
{
	return x + y;
}
int main()
{
	int a = Add(2, 2.2); //模板函数不允许自动类型转换,不能通过编译
	return 0;
}

因为模板函数不允许自动类型转换,所以不会将2自动转换为2.0,或是将2.2自动转换为2。

三、类模板

类模板是带类型参数的类,类的成员变量,成员函数可以使用类型参数,类模板不支持类型推断。

1.类模板语法

语法:

//类模板的声明
template 
class 类模板名{
    //...类中可以直接使用T类型    
};

template :是用来定义模板类型的关键字,也可以用class(不能用struct代替

typename :后面的字符表示为一个数据类型,可以被class替换

T :通用数据类型,可以被替换,但一般使用大写字母

注意:这样定义出来的仅仅是一个类的模板,而不是具体的类。 

//类模板的声明
template 
class Data{
public:
    Data(T a):dt(a){}

    T get_dt()
    {
        return this->dt;
    }

    void set_dt(T a)
    {
        this->dt = a;
    }

    void show()
    {
        cout            
关注
打赏
1665385461
查看更多评论
0.0395s