C++模板初阶小笔记

简介: C++模板初阶小笔记

目录

一.泛型编程

二.函数模板

1.函数模板语法梳理:

2.函数模板的实例化:

3.函数模板的显式实例化:

4.函数模板使用时的注意事项

三.类模板

1.类模板的语法梳理

2.类模板中声明和定义分离的成员函数

一.泛型编程
泛型编程:编写不依赖于具体数据类型的通用代码,是代码复用的一种手段。

二.函数模板
1.函数模板语法梳理:
C++中可以编写形参类型待定的函数模板。

假如我们现在要设计一个各种类型变量都通用的变量交换函数:

template
void swap(T1& Element1, T1& Element2)
{

T1 tem = Element1;
Element1 = Element2;
Element2 = tem;

}
函数模板书写格式:
template
返回值类型 函数名(形参列表){函数体}

template是定义模板的关键字
typename是定义模板待定变量类型的关键字
T1,T2...代表待定类型名,用于作为函数模板的形参类型名
注意函数模板本身并不是一个可调用的函数,由函数模板生成可调函数的过程是由编译器在编译阶段完成的
2.函数模板的实例化:
上面代码段中的swap就是一个函数模板,函数模板代表了一个函数家族,swap的形参Element1和Element2的类型都是待定的,实际调用swap函数时:

编译器会根据函数调用语句中传入函数的实参的类型生成对应的重载函数(编译器生成模板的重载函数的过程叫做函数模板的实例化),并调用重载函数。
也就是说,函数模板转变为可调函数的过程是在代码编译的阶段由编译器根据具体函数调用语句中实参的类型类完成的
比如:
template 定义函数模板
void swap(T1& Element1, T1& Element2)
{

T1 tem = Element1;
Element1 = Element2;
Element2 = tem;

}

class Date
{
public:

Date(char year = 0)
    :_year(year)
{
    cout << "constructor" << endl;
}

private:

char _year;

};

int main()
{

int a = 1;
int b = 2;
swap(a, b);                   交换一对整形变量

double d = 1.0;
double c = 2.0;
swap(d, c);                   交换一对浮点型变量

Date date1('b');
Date date2('c');
swap(date1, date2);           交换一对Date对象

return 0;

}

代码编译阶段编译器将函数模板转化为可调函数的过程图解:

这种函数模板的实例化方式称为隐式实例化(让编译器自己根据实参推演模板参数的实际类型),函数模板还可以显式实例化。
函数重载机制是支持函数模板化编程的底层机制
3.函数模板的显式实例化:
在函数调用语句的函数名后的<>中指定模板参数的实际类型。

template 定义函数模板
void swap(T1& Element1, T1& Element2)
{

T1 tem = Element1;
Element1 = Element2;
Element2 = tem;

}

int main ()
{

double d = 1.0;
double c = 2.0;
swap<double>(d, c);    
return 0;

}

4.函数模板使用时的注意事项
一个非模板函数可以和一个同名的函数模板同时存在。
// 专门处理int的加法函数
int Add(int left, int right)
{

return left + right;

}
// 通用加法函数
template
T Add(T left, T right)
{

return left + right;

}
void Test()
{

Add(1, 2);      //与非模板函数匹配,编译器不需要特化
Add<int>(1, 2); //调用编译器特化的Add版本(显式实例化模板)

}

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

// 专门处理int的加法函数
int Add(int left, int right)
{

return left + right;

}
// 通用加法函数
template
T1 Add(T1 left, T2 right)
{

return left + right;

}
void Test()
{

Add(1, 2);     // 与非函数模板类型完全匹配,不需要函数模板实例化
Add(1, 2.0);   // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数

}

模板实例化函数不能自动对实参进行强制类型转换,但普通函数可以自动对实参进行强制类型转换

三.类模板
1.类模板的语法梳理
类模板的定义格式:

template //类模板的未定变量类型列表
class Date //类模板名
{

 T1 _mem1; //类中未定类型的成员的声明
 T2 _nem2;
 ....      

};
T1,T2...具体的类型名在创建类对象时由用户自行指定
比如现在定义一个栈类的模板:

class Date
{
public:

Date(char year = 0)
    :_year(year)
{
    cout << "constructor" << endl;
}

private:

char _year;

};

template //Stack类模板
class Stack
{
public:

Stack(int capacity = 4, int nums = 0)    //类的构造函数
    :_data = nullptr                     //构造函数初始化列表
    , _capacity = capacity
    , _nums = nums
{
    _data = new T[_capacity];             //为栈申请初始的堆区空间
}

~Stack()                                 //类的析构函数
{
    delete[] _data;                         //将栈申请的堆区空间还给系统
    _data = nullptr;
}

private:

T* _data;
int _capacity;
int _nums;

};

int main()
{

Stack<int> a;           //创建一个存储int类型数据的栈对象

Stack<double>b;            //创建一个存储double类型数据的栈对象

Stack<Date>c;           //创建一个存储Date对象的栈对象

return 0;

}

注意:

用类模板的方式定义的栈对象使用起来十分方便,可以用于存储各种类型的数据(一般来说实现一个栈类需要上百行代码,实现三种数据类型的栈就要三份代码,然而如果使用模板型编程方式,代码书写量就可以大大减少)

2.类模板中声明和定义分离的成员函数
如果类模板中的成员函数要放在类外进行定义时,需要加上模板参数列表,比如:

template
class Stack
{
public:

Stack(int capacity = 4, int nums = 0)    //类的构造函数
    :_data = nullptr                     //构造函数初始化列表
    , _capacity = capacity
    , _nums = nums
{
    _data = new T[_capacity];             //为栈申请初始的堆区空间
}

~Stack();     //类的析构函数的声明, 将析构函数的定义放在类模板外面

private:

T* _data;
int _capacity;
int _nums;

};

template
Stack::~Stack() //类的析构函数的定义
{

delete[] _data;
_data = nullptr;

}
模板型编程模式可以让代码变得更简洁,简洁的代码维护起来才更加的方便高效。

相关文章
|
2月前
|
存储 算法 C++
C++ STL 初探:打开标准模板库的大门
C++ STL 初探:打开标准模板库的大门
112 10
|
27天前
|
安全 编译器 C++
【C++11】可变模板参数详解
本文详细介绍了C++11引入的可变模板参数,这是一种允许模板接受任意数量和类型参数的强大工具。文章从基本概念入手,讲解了可变模板参数的语法、参数包的展开方法,以及如何结合递归调用、折叠表达式等技术实现高效编程。通过具体示例,如打印任意数量参数、类型安全的`printf`替代方案等,展示了其在实际开发中的应用。最后,文章讨论了性能优化策略和常见问题,帮助读者更好地理解和使用这一高级C++特性。
42 4
|
27天前
|
算法 编译器 C++
【C++】模板详细讲解(含反向迭代器)
C++模板是泛型编程的核心,允许编写与类型无关的代码,提高代码复用性和灵活性。模板分为函数模板和类模板,支持隐式和显式实例化,以及特化(全特化和偏特化)。C++标准库广泛使用模板,如容器、迭代器、算法和函数对象等,以支持高效、灵活的编程。反向迭代器通过对正向迭代器的封装,实现了逆序遍历的功能。
34 3
|
1月前
|
编译器 C++
【c++】模板详解(1)
本文介绍了C++中的模板概念,包括函数模板和类模板,强调了模板作为泛型编程基础的重要性。函数模板允许创建类型无关的函数,类模板则能根据不同的类型生成不同的类。文章通过具体示例详细解释了模板的定义、实例化及匹配原则,帮助读者理解模板机制,为学习STL打下基础。
31 0
|
2月前
|
编译器 程序员 C++
【C++打怪之路Lv7】-- 模板初阶
【C++打怪之路Lv7】-- 模板初阶
18 1
|
2月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
60 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
88 2
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
45 2
|
2月前
|
存储 算法 编译器
【C++】初识C++模板与STL
【C++】初识C++模板与STL
|
2月前
|
编译器 C++
【C++】模板进阶:深入解析模板特化
【C++】模板进阶:深入解析模板特化
104 0