1.模板
(1)简介
cpp
复制代码
/*
* C++提高编程
* 本阶段主要针对C++泛型编程 和 STL技术 做详细讲解,探讨C++更深层的使用
*
* 1.模板
* 概念:模板就是建立通用的模具,大大提高复用性
*
* 特点:
* 模板不可以直接使用,它只是一个框架
* 模板的通用并不是万能的
*/
int main() {
return 0;
}
(2)函数模板
cpp
复制代码
/*
* 函数模板
* 建立一个通用函数,其函数返回值类型和形参类型可以不具体指定,用一个虚拟的类型来代表。
* 语法:template<typename T>
* 函数声明或者定义
* 解释:template--声明创建模板
* tempname --表明其后面的符号是一种数据类型,可用class替换
* T --通用的数据类型,名称可以替换,通常为大写字母
*
* 隐式模板 mySwap(a,b);
* 显示模板 mySwap<int>(a,b);
*
* 注意事项
* 自动类型推导,需要推导出一致的数据类型T,才可以使用
* 模板必须要确定出T的数据类型,才可以使用。
*/
//函数模板
template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型
void mySwap(T &a,T &b){
T temp=a;
a=b;
b=temp;
}
template<typename T>
void func(){
cout<<"fun 调用"<<endl;
}
void test01(){
int a=10;
int b=20;
//1.自动类型推导
mySwap(a,b);
//2.显示指定类型
mySwap<int>(a,b);
cout<<"a="<<a<<endl;
cout<<"b="<<b<<endl;
}
int main() {
test01();
func<int>();
return 0;
}
(3)函数模板案例
cpp
复制代码
/*
* 函数模板案例
*
* 描述:
* 利用函数模板封装一个排序的函数,可以对不同数据类型素组进行排序
* 排序规则从大到小,排序算法为选择排序
* 分别利用char数组和int数组进行测试
*
*/
template<class T>
void mySort(T arr[],int len){
for(int i=0;i<len;i++){
int max=i; //认定最大值得小标
for(int j=i+1;j<len;j++){
//认定的最大值比遍历出的数组要小,说明j下表的数值大
if(arr[max]<arr[j]){
max=j;
}
}
if(max!=i){
T temp=arr[max];
arr[max]=arr[i];
arr[i]=temp;
}
}
}
//冒泡排序
template<typename T>
void sayArray(T arr[],int len) {
cout << "数组元素为:" << sizeof(arr) <<endl;
for (int i = 0; i < len; i++) {
cout << arr[i] << endl;
}
}
void test01() {
char charArr[]="abcdef";
int num=sizeof (charArr)/ sizeof(char);
mySort(charArr,num);
sayArray(charArr,num);
}
int main() {
test01();
return 0;
}
(4)普通模板和函数模板的调用规则
cpp
复制代码
/*
* 普通函数和函数模板的调用规则
* 如果函数模板和普通函数都可以实现,优先调用普通函数
* 可以通过空模板参数列表来强制调用函数模板 myPrint<>(2,2);
* 函数模板也可以发生重载
* 如果函数模板可以产生更好的匹配,优先调用函数模板
*/
void myPrint(int a, int b) {
cout << "调用的普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b) {
cout << "调用的模板" << endl;
}
//函数模板 重载
template<typename T>
void myPrint(T a, T b, int) {
cout << "调用的模板" << endl;
}
int main() {
myPrint(1, 2);
//空模板参数列表,强制调用函模板
myPrint<>(2, 2);
//如果函数模板产生更好的匹配,优先调用函数模板
myPrint('1', 'a');
return 0;
}
(5)模板的局限性
cpp
复制代码
/*
* 模板的局限性
* 模板的通用性并不是万能的
* 有些特定数据类型,需要用具体化方式做特殊实现
*/
class Person {
public:
string name;
int age;
Person(string name, int age) {
this->name = name;
this->age = age;
}
bool operator==(Person &p) {
cout<<"operator== 函数被调用了"<<endl;
if (this->name == p.name && this->age == p.age) {
return true;
} else {
return false;
}
}
};
//对比两个数据是否相等
template<class T>
bool myCompare(T &a, T &b) {
if (a == b) {
return true;
} else {
return false;
}
}
void test01() {
int a = 20;
int b = 20;
bool ret = myCompare(a, b);
if (ret) {
cout << "a==b" << endl;
} else {
cout << "a!=b" << endl;
}
}
void test02() {
Person p1("张三", 10);
Person p2("李四", 10);
bool ret = myCompare(p1, p2);
cout << "p1==p2:" << ret << endl;
}
int main() {
test01();
test02();
return 0;
}
(7)类模板
(1)类模板开胃菜
cpp
复制代码
/*
* 类模板
* 类模板语法:
* 建立一个通用类,类中的成员 数据类型可以不具体定制,用一个虚拟的类型来代表。
*
* 语法:
* template<typename T>
* 类
* 解释:
* template -- 声明创建模板
* typename -- 表明其后面的符号是一种数据类型,可以用class'代替
* T -- 通用的数据类型,名称可以替换,通常为大写字母
*
*/
//类模板
template<class nameType, class ageType>
class Person {
public:
nameType name;
ageType age;
Person(nameType name, ageType age) {
this->name = name;
this->age = age;
}
void showPerson() {
cout << "name=" << this->name << ";age=" << age << endl;
}
};
void test01() {
Person<string, int> p1("孙大圣", 28);
p1.showPerson();
Person p2("孙大圣2", "282");
p2.showPerson();
}
int main() {
test01();
return 0;
}
(2)类模板与函数模板的区别
cpp
复制代码
/*
* 类模板和函数模板区别
* 1.类模板没有自动类型推导的使用 自己使用的版本为C++20,以支持自动推导
* 。类模板在模板参数列表中可以有默认参数
*
*/
//类模板与函数模板的区别
template<class nameType, class ageType=string>
class Person {
public:
nameType name;
ageType age;
Person(nameType name, ageType age) {
this->name = name;
this->age = age;
}
void showPerson() {
cout << "name=" << this->name << ";age=" << age << endl;
}
};
//1.类模板没有自动类型推导使用方式
void test01() {
Person p1("孙悟空", 1000);
}
//2.类模板在模板参数列表中可以有默认参数
void test02() {
Person p2("aaa", 123);
p2.showPerson();
Person p3("bbb", '234');
p3.showPerson();
}
int main() {
test02();
return 0;
}
(3)类模板中成员函数创建时机
cpp
复制代码
/*
* 类模板中成员函数创建时机
*
* 类模板中成员函数和普通类中成员函数创建时机是有区别的
* 普通泪中的成员函数一开始就可以创建
* 类模板中的成员函数在调用时候才创建
*
*/
class Person1 {
public:
void showPerson1() {
cout << "Person1" << endl;
}
};
class Person2 {
public:
void showPerson2() {
cout << "Person2 show" << endl;
}
};
template<class T>
class myClass {
public:
T obj;
//类模板中的成员函数
void func1() {
obj.showPerson1();
}
void func2() {
obj.showPerson2();
}
};
void test01() {
myClass<Person1> m;
m.func1();
//m.func2(); //报错,提示没有这个方法
myClass<Person2> m2;
m2.func2();
}
int main() {
test01();
return 0;
}
(4)类模板对象做函数参数
cpp
复制代码
*
* 类模板对象做函数参数
*
* 学习目标:类模板实例化出的对象,向函数传参的方式
*
* 三种方式:
* 1.指定传入的类型:直接显示对象的数据类型
* 2.参数模板化:将对象中的参数变为模板进行传递
* 3.整个类模板化:将这个对象类型 模板化进行传递
*
*/
template<class T1, class T2>
class Person {
public:
T1 name;
T2 age;
Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
void showPerson() {
cout << "name=" << name << ";age=" << age << endl;
}
};
//1.指定传入类型
void printPerson1(Person<string, int> &p) {
p.showPerson();
}
void test01() {
Person<string, int> p("孙悟空", 100);
printPerson1(p);
}
template<class T1, class T2>
void printPerson2(Person<T1, T2> &p) {
p.showPerson();
cout << "T1类型为:" << typeid(T1).name() << endl;
cout << "T2类型为:" << typeid(T1).name() << endl;
}
//2.参数模板花
void test02() {
Person<string, int> p("猪八戒", 90);
printPerson2(p);
}
template<class T>
void printPerson3(T p) {
p.showPerson();
}
//3.整个类模板化
void test03() {
Person<string, int> p("唐山", 20);
printPerson3(p);
}
int main() {
cout << "test01()" << endl;
test01();
cout << "test02()" << endl;
test02();
cout << "test03()" << endl;
test03();
return 0;
}
(5)类模板与继承
cpp
复制代码
/*
* 类模板与继承
*
* 当类模板碰到继承时,需要注意:
* 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中的T的类型
* 如果不指定,编译器无法给子类分配内存
* 如果想灵活指定出父类中T的类型,子类也需要变为类模板
*
*/
//类模板与继承
template<class T>
class Base {
T m;
};
//class Son:public Base{ //错误,必须要知道父类中的T类型,才能继承给子类
//
//};
class Son : public Base<int> {
};
void test01() {
Son son;
}
//如果想灵活指定父类中T类型,子类也需要变类模板
template<class T1, class T2>
class Son2 : public Base<T2> {
public:
T1 obj;
Son2() {
cout << "T1类型为:" << typeid(T1).name() << endl;
cout << "T2类型为:" << typeid(T2).name() << endl;
}
};
void test02() {
Son2<int, char> s2;
}
int main() {
test01();
test02();
return 0;
}
(6)类模板成员函数类外实现
cpp
复制代码
/*
* 类模板成员函数类外实现
* 学习目标:能够掌握类模板中的成员函数类外实现
*/
template<class T1,class T2>
class Person{
public:
T1 name;
T2 age;
Person(T1 name,T2 age);
void showPerson();
};
//类模板 成员函数类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){
this->name=name;
this->age=age;
}
//成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson(){
cout<<"姓名:"<<name<<";年龄="<<age<<endl;
}
void test01(){
Person<string,int> p("AAA",18);
p.showPerson();
Person p2("AAA",18);
p2.showPerson();
}
int main() {
test01();
return 0;
}
(7)类模板与友元
cpp
复制代码
/*
* 类模板与友元
*
* 学习目标:
* 掌握类模板配合友元函数的类内和类外实现
* 全局函数类内实现 -- 直接在类内声明友元即可
* 全局函数类外实现 -- 需要提前让编译器知道全局函数的存在
*/
//让编译器提前知道Person类的存在
template<class T1, class T2>
class Person;
//类外实现
//加空模板参数列表
//如果全局函数 是类外实现,需要让编译器提前知道这个函数的存在
template<class T1, class T2>
void printPerson2(Person<T1, T2> p) {
cout << "类外实现:姓名:" << p.name << ";年龄:" << p.age << endl;
}
//通过全局函数打印Perosn信息
template<class T1, class T2>
class Person {
//全局函数 类内实现
friend void printPerson(Person<T1, T2> p) {
cout << "姓名:" << p.name << ";年龄:" << p.age << endl;
}
//全局函数 类外实现
friend void printPerson2();
public:
T1 name;
T2 age;
Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
};
//1.全局函数类内实现
void test01() {
Person p1("Tom", 18);
printPerson(p1);
}
//1.全局函数类外实现
void test02() {
Person p2("Dog", 22);
printPerson(p2);
}
int main() {
test01();
test02();
return 0;
}
(8)类模板案例
cpp
复制代码
未学习
https://www.bilibili.com/video/BV1et411b73Z?p=183