前言:在C++编程世界中,模板是一个强大的工具,它使得程序员能够编写更加通用、灵活和可重用的代码。通过模板,我们可以编写与类型无关的代码,这些代码可以在编译时根据所需的具体类型进行实例化。本文将带你走进C++模板的初阶世界,探索泛型编程的基石
泛型编程: 编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
我们来看看之前如何实现一个交换函数
// 函数重载
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;
}
int main()
{
int a = 1, b = 9;
double c = 1.1, d = 8.9;
char e = 'a', f = 'b';
Swap(a, b); Swap(c, d); Swap(e, f);
cout << a << " " << b << endl;
cout << c << " " << d << endl;
cout << e << " " << f << endl;
return 0;
}
在编程中,我们经常遇到需要处理不同类型数据的场景。为了处理这些类型,我们通常需要编写多个函数或类,每个函数或类都针对特定的数据类型进行实现。这不仅增加了代码的冗余度,也降低了代码的可维护性和可重用性
。模板的引入就是为了解决这个问题。通过使用模板,我们可以编写与类型无关的代码,这些代码可以在编译时根据所需的具体类型进行实例化,从而生成针对特定类型的代码
根据上面的示例代码我们能够用模板修改
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
格式:template<typename T> T 表示类型
template < typename T> 声明了一个模板参数T,它表示任意类型
。在函数参数和返回类型中,我们都使用了T,这样该函数就可以处理任何类型的数据了
有了这个函数就能实现上述三个交换函数
注意: typename是用来定义模板参数关键字,也可以使用class (切记:
不能使用struct代替class
)
函数模板是一个蓝图,它本身并不是函数
,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用
。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于字符类型也是如此
用不同类型的参数使用函数模板时,称为函数模板的实例化 模板参数实例化分为:
隐式实例化
和显式实例化
隐式实例化:让编译器根据实参推演模板参数的实际类型
// 隐式实例化
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
// 在这里要注意一点,在模板中,编译器一般不会进行类型转换操作
//Add(a1, d1); false
// 虽然编译器不会进行类型转换,但是我们能自己来强制转化或者显式实例化
Add(a1, (int)d1);
return 0;
}
模板参数列表中只有一个T时,无法将两个类型不同的放在一起推演,编译器无法确定此处到底该将T确定什么类型而报错
显式实例化:在函数名后的<>中指定模板参数的实际类型
// 显式实例化
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
// 显式实例化
Add<int>(a1, d1);
return 0;
}
注意:
模板参数的匹配原则:
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template<class T>
T Add(T left, T right)
{
return left + right;
}
int main()
{
Add(1314, 520); // 与非模板函数匹配,优先调用非模板函数
Add<int>(1314.0, 520.0); // 调用编译器特化的Add版本
}
int Add
能够和T Add
同时存在,在调用函数时若参数和非模板函数匹配,那么编译器会优先调用非模板函数若非模板函数;不匹配或模板函数更匹配,那么编译器会优先调用模板函数
类模板是对一批仅成员数据类型不同的类的抽象。通过为这一批类组成的类家族创建一个类模板,并提供一套程序代码,程序员可以生成多种具体的类,从而显著提高编程效率
template<class T1, class T2, ..., class Tn>
class pxt//类模板名
{
// 类内成员定义
};
我们来定义一个简单的顺序表
template<class T>
class Vector
{
public:
Vector(size_t capacity = 10)
: _pData(new T[capacity])
, _size(0)
, _capacity(capacity)
{}
// 使用析构函数演示:在类中声明,在类外定义。
~Vector();
T& operator[](size_t pos)
{
assert(pos < _size);
return _pData[pos];
}
private:
T* _pData;
size_t _size;
size_t _capacity;
};
// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T> //这里不要忘记带上
Vector<T>::~Vector()
{
if (_pData)
delete[] _pData;
_size = _capacity = 0;
}
关于类模板其实就是将原来实际类型的位置变成T
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类
关于类模板的实例化必须显示实例化,类模板没有隐式推演
// Vector类名,Vector<int>才是类型
Vector<int> v1;
Vector<double> v2;
🐫驼峰命名法(CamelCase): 是电脑程序编写时常用的一套命名规则,通过混合使用大小写字母来构成变量、函数、类名等的名字。这种命名方式有助于提高代码的可读性和可维护性
驼峰命名法在多种编程语言中都有广泛应用,如Java、C#、JavaScript、Python等。在编写代码时,根据命名对象的类型(如变量、函数、类等)选择合适的驼峰命名法可以提高代码的可读性和可维护性!!!
🐼命名规则: 当变量名、函数名或类名由多个单词组成时,第一个单词以小写字母开始,从第二个单词开始以后的每个单词的首字母都采用大写字母。
// 例如:
myFirstName
printEmployeePaychecks
🐋驼峰命名法的分类
🐟小驼峰法(lower camel case):
变量名、方法名、属性名
等🐬大驼峰法(upper camel case):
类名、接口名、常量名
等。🐷优点
🐨注意事项
总之,驼峰命名法是一种简单、清晰、易读的命名方式,在程序编写中被广泛使用。通过合理使用驼峰命名法,可以提高代码的可读性和可维护性,降低编程错误率
总结: 在完成C++模板初阶的学习之后,我们可以深刻地感受到模板在C++编程中的强大与灵活性。模板作为C++编程语言的一个重要特性,为我们提供了一种在编译时生成特定类型代码的机制,从而实现了代码的重用和泛型编程。下节我们将进入C++ STL,对STL进行深入发掘 谢谢大家支持本篇到这里就结束了,祝大家天天开心!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有