C++模版复习
Sometime i feel tried
But all my scars wil be my tatoo
C++除了面向对象编程的思想 , 还有一种思想叫做泛型编程,主要利用的技术就是模版
1. 模版
1.1 模版的概念
模版的特点
- 模版不可以直接使用,它只是一个框架
- 模版的通用并不是万能的
C++
提供两种模版机制:函数模版 和 类模版
1.2 函数模版
1.2.1 函数模版的作用 :
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法:
//函数声明或定义
template<typename T>
函数
解释:
template
--- 声明创建模版
typename
--- 其后面的符号是一种数据类型 , 可以用class
代替
T
--- 通用的数据类型,名称可以替换,通常为大写字母
//函数模版声明
template<typename T>
void mySwap( T &a, T &b )
{
T temp = a;
a = b;
b = temp;
}
//函数模版的使用
1.自动类型推导
mySwap(a,b);
2.显示指定类型
mySwap<int>(a,b);
1.2.2 函数模版注意事项
注意事项:
- 自动类型推导 , 必须推导出一致的数据类型
T
,才可以使用 - 模版必须要确定出
T
的数据类型,才可以使用
template <class T>
void func(){ };
//erorr func(); 因为上面函数使用了函数模版,但是没有指明T的类型(没有使用T)
1.2.3 函数模版案例
详见Clion 用了选择排序法
1.2.4 普通函数与函数模版的区别
普通函数与函数模版区别 :
myAddSum1()---普通函数 myAddSum2()----函数模版
-
普通函数调用时可以发生自动类型转换(隐式类型转换)
int a = 10; int b = 20; char c = 'c'; //a-97 c-99 cout<< myAddSum1(a,c)<<endl; //发生隐式类型转换
-
函数模版调用时,如果利用自动类型推导,不会发生隐式类型转换
cout<<myAddSum2(a,c)<<endl; //❌会报错error 因为不会发生隐式类型转换
-
如果利用显示指定类型的方式,可以发生隐式类型转换
cout<<myAddSum2<int>(a,c)<<endl;//✅不会报错
总结 : 建议使用显示指定类型的方式,调用函数模版,因为可以自己确定通用类型
T
1.2.5 普通函数与函数模版的调用规则
调用规则:
myPrint()---普通函数。 myPrint()---函数模版
-
如果函数模版和普通函数都可以实现,优先调用普通函数✅
myPrint(a,b);----调用普通函数
-
可以通过空模版参数列表来强调函数模版
myPrint<>(a,b);----调用函数模版
-
函数模版可以发生重载
-
如果函数模版可以产生更好的匹配,优先调用函数模版
总结:实际开发中,最好不要同时提供,否则容易出现二义性
1.2.6模版的局限性
局限性:
- 模版的通用性并不是万能的
//当想要实现比较的一个函数
//利用具体化Person的版本实现代码,具体化优先调用
template<> bool myCompare(Person &p1,Person &p2)
{
if(p1.m_Name==p2.m_Name && p1.m_Age==p2.m_Age)
{
return true;
}
else
{
return false;
}
}
总结:
- 利用具体化的模版,可以解决自定义类型的通用化
- 学习模版并不是为了写模版,而是在
STL
中能够运用系统提供的模版
1.3类模版
1.3.1类模版语法
类模版作用:
- 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表
语法:
template<typename T> ······就不介绍了,同上
类
示例:
template<class N,class A>
class Person
{
public:
N Name;
A Age;
Person(N name,A age)
{
this.Name=name;
this.Age=age;
}
}
//实现调用
Person<string,int>person("Kolin",999);
1.3.2类模版与函数模版区别
🌟类模版与函数模版区别主要有两点:
- 类模版没有自动类型推导的使用方式
//详细🔎见上
Person p("Kolin",1000);----error,无法自动类型推导
Person<string,int>p("Kolin",1000);----正确,只能用显示指定类型
- 类模版在模版参数列表中可以有默认参数
template<class N,class A = int>‼️
class Person
{
·····
}
Person<string>p("Kolin" ,999);‼️
总结:
- 🌟类模版使用只能用显示指定类型方式
- 🌟类模版中的模版参数列表可以有默认参数
1.3.3 类模版中成员函数创建时机
类模版中成员函数和普通类中成员函数创建时机是有区别的:
- 普通类中的成员函数一开始就可以创建
- 类模版中的成员函数在调用时才创建
1.3.4类模版对象做函数参数
学习目标:
- 类模版实例化出的对象,向函数传参的方式
一共三种传入方式:
-
指定传入的类型---直接显示对象的数据类型(最常用🌟)
//详细🔎前提见上 void printPerson1(Person<string,int> &p) <---指定传入类型 { p.showPerson(); } Person<string ,int>p("Kolin",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(T2).name()<<endl;
}
Person<string ,int>p("Acher",90);
printPerson2(p);
- 整个类模版化 ---将这个对象类型 模版化进行传递
//详细🔎前提见上
template<class T>
void printPerson3(T &p) <---整个类模版化
{
p.showPerson();
//补充 查看模版中推导出的类型👇
cout<<"T的类型:"<<typeid(T).name()<<endl;
}
Person<string ,int>p("Napcats",30);
printPerson3(p);
1.3.5类模版与继承
当类模版碰到继承时,需要注意一下几点:
- 当子类继承父类是一个类模版时,子类在声明的时候,要指定出父类中T的类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也需变为类模版
//父类类模版
template<class T>
class Base
{
T m;
};
//子类类模版
class Son: public Base<int> <---必须指定父类中T的类型
{
};
//如果想灵活指定父类中的T类型,子类也需变成类模版
template<class T1,class T2>
class Son2 : public Base<T2>
{
T1 obj;
};
//实例化
Son2<int,char>S2;
总结:如果父类是类模版,子类需要指定出父类中T
的数据类型,不然不给分配内存空间
1.3.6类模版成员函数类外实现
类模版:
template <class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age);//构造函数未实现
void showPerson();//成员函数未实现
T1 Name;//成员属性
T2 Age;
}
类模版的构造函数的类外实现:
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<<"·····"<<endl;
}
总结:类模版的函数,要在外部实现,比起平常的(作用域::) ,还要加上类模版的参数列表(作用域<T···>::)
1.3.7类模版分离式编译
问题:
- 类模版中成员函数创建时机是在调用阶段,导致份文件编写时链接🔗不到
解决:
- 解决方式1:直接包含.cpp源文件
- 解决方式2(常用🌟):将声明和实现写到同一个文件中,并更改后缀名为.hpp , hpp是约定的名称,并不是强制
只能写个人理解了:
- 就是类模版中成员函数创建时机是在调用阶段,所以直接引入.h会引发链接错误
- 所以用上面两个解决方法来实现
- 第一种是直接引入.cpp在主函数上声明,这样可以解决无法连接到函数实现的问题
- 第二种方法是把.h .cpp直接写成一个,命名后缀改为.hpp,这个就是相当于类模版分离式编译专用nickname了
1.3.8类模版与友元
哭了 辛苦写的不小心复制粘贴全没了(还有上一节)
就这样吧 呜呜呜呜呜呜呜 幸好还有版本控制呜呜呜呜😭
就说一点个人理解吧:
- friend友元函数在类内是全局函数,不属于类,不是成员函数
- 如果要在外部实现全局函数(配合类模版),要先声明让编译器知道,还要给类内声明加空参列表(<>)·····
- 详细二次复习还是再看看视频,加深理解🔎
posted on 2022-06-04 16:26 AcherLoveCode 阅读(24) 评论(0) 编辑 收藏 举报