1 基础概念
2 函数模板
2.1 函数模板语法
示例:两种调用模版的方式。
2.2 函数模版注意事项
2.3 函数模板案例
#include <iostream>
using namespace std;
#include <string>
//函数模版案例—对不同的数组进行排序
//选择排序,从大到小
template<typename T> //声明一个模版,告诉编译器以后的T不要报错
void Swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<class T>
void Sort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int max = i; //认定数组i下标处的最大
for (int j = i + 1; j < len; j++)
{
if (arr[max] < arr[j])
{
max = j; //经过第一轮找到最大的了
}
}
//如果最大值不是i,则交换两个值的位置
if (max != i)
{
Swap(arr[max], arr[i]);
}
}
}
//提供打印数组模版
template <class T>
void printArray(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
}
void test01()
{
char charArr[] = "badefc";
int num = sizeof(charArr) / sizeof(char);
Sort(charArr,num );
printArray(charArr, num);
}
int main()
{
test01();
system("pause");
return 0;
}
2.4 普通函数与函数模板的区别
2.5 普通函数和函数模板的调用规则
当普通函数和函数模版发生函数重载的时候。
1、 此时如果给这样一段代码调用普通还是模版?
调用普通函数。 普通函数优先。
就算普通函数只有声明,没有具体实现,还是调用普通函数,代码报错。
2、 通过空模版列表,强制调用函数模版
此时调用模版函数。
3、函数模版也可以重载。
4、如果函数模版更好匹配,优先调用函数模版
此时调用普通函数还是函数模版呢?(普通函数虽然形参是int但是可以发生隐式类型转换,也可以调用)
但仍然调用模版,因为模版更匹配。
2.6 模板的局限性
此时传入Person数据类型不可以运行,因为自定义的数据类型特殊。因此我们可以做当遇见这种数据类型时,调用下面这个代码。
将T数据类型换为Person。
3 类模板
3.1 类模板语法
一个类模版就写好了。如何使用呢?
示例代码如下:
#include <iostream>
using namespace std;
#include <string>
//类模版
//template<class N>
//类中包含了string和int两个属性,因此只定义一个类型是不够的
template<class NameType,class AgeType>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_name = name;
this->m_age = age;
}
void showPerson()
{
cout << "name:" << this->m_name << "age:" << this->m_age << endl;
}
NameType m_name;
AgeType m_age;
};
void test01()
{
Person<string, int> p1("孙悟空",180200);
p1.showPerson();
}
int main()
{
test01();
system("pause");
return 0;
}
3.2 类模板与函数模板的区别
示例代码如下:
#include <iostream>
using namespace std;
#include <string>
//类模版与函数模版区别
template<class NameType, class AgeType=int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_name = name;
this->m_age = age;
}
void showPerson()
{
cout << "name:" << this->m_name << "age:" << this->m_age << endl;
}
NameType m_name;
AgeType m_age;
};
//1、类模版没有自动推导的使用方式
void test01()
{
//Person p1("孙悟空", 180200); 错误类模板没有自动推导类型
Person<string, int> p1("孙悟空", 180200);
p1.showPerson();
}
//2、类模版在模版参数列表中可以有默认参数
void test02()
{
Person<string> p1("猪八戒", 10000);
p1.showPerson();
}
int main()
{
test02();
system("pause");
return 0;
}
3.3 类模板中成员函数创建时机
3.4 类模板对象做函数参数
直接把模版参数列表都给函数形参。
三种方式都可以做到。
#include <iostream>
using namespace std;
#include <string>
//类模版对象做函数参数
template<class NameType, class AgeType = int>
class Person
{
public:
Person(NameType name, AgeType age)
{
this->m_name = name;
this->m_age = age;
}
void showPerson()
{
cout << "name:" << this->m_name << "age:" << this->m_age << endl;
}
NameType m_name;
AgeType m_age;
};
//1、指定传入类型
void printPerson1(Person<string, int>&p1)
{
p1.showPerson();
}
void test01()
{
Person<string,int>p1("孙悟空", 180200);
printPerson1(p1);
}
//2、参数模板化
template<class T1,class T2>
void printPerson2(Person<T1, T2>& p2)
{
p2.showPerson();
}
void test02()
{
Person<string, int>p2("猪八戒", 1000);
printPerson1(p2);
}
//3、整个类模版化
template<class T>
void printPerson3(T& p3)
{
p3.showPerson();
}
void test03()
{
Person<string, int>p3("唐僧", 20);
printPerson1(p3);
}
int main()
{
test03();
system("pause");
return 0;
}
3.5 类模板与继承
在继承后面指明继承的数据类型。
但是这种方法把继承子类的数据类型固定了,如果需要改一下,就要重新写继承。因此可以把子类也写成模版,
示例代码;
#include <iostream>
using namespace std;
#include <string>
//类模版与继承
template<class T>
class Base
{
public:
T m;
};
//class Son :public Base //错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Base<int> //类型只能为Int
{
public:
};
void test01()
{
Son s1;
}
//如果想灵活的指定父类的T类型,子类也需要写成类模板
template <class T1,class T2>
class Son2 :public Base<T2>
{
public:
T1 abs;
};
void test02()
{
Son2<int,char>s2;
}
int main()
{
//test03();
system("pause");
return 0;
}
3.6 类模板成员函数类外实现
#include <iostream>
using namespace std;
#include <string>
//类模版成员函数类外实现
template<class T1,class T2>
class Person
{
public:
//成员函数类内声明
Person(T1 name, T2 age);
void showPerson();
T1 m_name;
T2 m_age;
};
//构造函数 类外实现
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_name = name;
this->m_age = age;
}
//成员函数的类外实现
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_name << "年龄" << this->m_age << endl;
}
void test01()
{
Person<string, int>P("Tom", 20);
}
int main()
{
system("pause");
return 0;
}
3.7 类模板分文件编写
我们将代码分开:
此时看似正常,但是运行报错。
这两行代码无法解析。
将头文件改为.cpp,程序正常运行。但是直接包含源文件这种方法一般不用,第二种解决方案。
将cpp和头文件内容和起来。
#pragma once
#include <iostream>
using namespace std;
#include <string>
template<class T1, class T2>
class Person
{
public:
Person(T1 name, T2 age);
void showPerson();
T1 m_name;
T2 m_age;
};
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age)
{
this->m_name = name;
this->m_age = age;
}
template<class T1, class T2>
void Person<T1, T2>::showPerson()
{
cout << "姓名:" << this->m_name << "年龄" << this->m_age << endl;
}
3.8 类模板与友元
在类外实现全局函数,代码报错。
因此需要前面让编译器知道。