目录
1.0 模板概论
1.1 函数模板
1.1.1 模板声明及模板使用小案例
1.1.2 函数模板和普通函数的区别以及调用规则
1.1.3 函数机制和模板局限性
1.1.4 类模板
1.1.5 案例:myarray
1.0 模板概论
C++提供了函数模板。所谓函数模板,实际上是建立了一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就是函数模板。
凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只要在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。
1.1 函数模板
1.1.1 模板声明及模板使用小案例
C++提供了函数模板。所谓函数模板,实际上是建立了一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就是函数模板。
凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只要在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。
1.1.1 模板声明及模板使用小案例
1.实现任意两个数交换
void myswap(T& a,T& b) { T temp = a; a = b; b = temp; } void test01() { int a = 1; int b = 2; float c = 1.1; float d = 2.2; myswap(a,b); myswap(c,d); cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; cout << "d = " << d << endl; }/home/lhw/桌面/C++/day8/cmake-build-debug/day8 a = 2 b = 1 c = 2.2 d = 1.1
2.模板声明
template
这里的T是指代通用数据类型,告诉编译器如果下面的函数或者类中出现T不要报错。
3.模板使用
I.自动类型推导
自动判断a,b是int类型,必须推导出是一致的T数据类型,才能正确的使用模板。
II.显示指定类型
void test01() { int a = 1; int b = 2; float c = 1.1; float d = 2.2; myswap(a,b); myswap (c,d); cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; cout << "d = " << d << endl; } III.模板不能单独使用,必须指定T才可以使用
4.案例:对char和int数组进行排序
void myswap(T& a,T& b)
{
T temp = a;
a = b;
b = temp;
}
template
void mySort(TE arr[],int len)
{
for(int i=0;i
/home/lhw/桌面/C++/day8/cmake-build-debug/day8
wroolllhed
9876543
1.1.2 函数模板和普通函数的区别以及调用规则
1. 函数模板和普通函数的区别
void test03() { int a = 10; int b = 20; char c = 'c'; //myadd1(a,c); error 如果使用自动类型推导,是不允许发生隐式类型转换的 cout << myadd2(a,c) << endl; //普通函数允许发生隐式类型转换 }函数模板如果使用自动类型推导,是不允许发生隐式类型转换的。
普通函数允许发生隐式类型转换
2. 函数模板和普通函数的调用规则
I.如果函数模板和普通函数都可以调用,那么优先调用普通函数。
templatevoid printmt(T a,T b) { cout << "template function is running" << endl; } void printmt(int a,int b) { cout << "original function is running" << endl; } void test04() { /home/lhw/桌面/C++/day8/cmake-build-debug/day8 original function is runningII.如果想强制调用函数模板,可以使用空模板参数列表
templatevoid printmt(T a,T b) { cout << "template function is running" << endl; } void printmt(int a,int b) { cout << "original function is running" << endl; } void test04() { printmt<>(10,20); } III.函数模板也可以发生函数重载
templatevoid printmt(T a,T b) { cout << "template function 2 is running" << endl; } template void printmt(T a,T b,T c) { cout << "template function 3 is running" << endl; } void printmt(int a,int b) { cout << "original function is running" << endl; } void test04() { printmt<>(10,20,30); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 template function 3 is runningIV.如果函数模板能产生更好的转换,优先选择函数模板
templatevoid printmt(T a,T b) { cout << "template function 2 is running" << endl; } template void printmt(T a,T b,T c) { cout << "template function 3 is running" << endl; } void printmt(int a,int b) { cout << "original function is running" << endl; } void test04() { printmt<>('a','b'); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 template function 2 is running
1.1.3 函数机制和模板局限性
1.局限性
I.编译器并不是把函数模板处理成能够处理任何类型的数据---通过具体化解决
代码:看两个变量是否相等
class Person { public: Person(string name,int age) { this->name = name; this->age = age; } string name; int age; }; templatebool mycompare(T& a,T& b) { if(a==b) return true; } template<> bool mycompare(Person& a,Person& b) { if(a.name==b.name && a.age==b.age) return true; else return false; } void test05() { int a = 10; int b = 10; Person p1("Tom",19); Person p2("Tom",19); bool ret = mycompare(a,b); if(ret) { cout << "a = b" << endl; } else { cout << "a !=b "; } } II.函数模板通过具体类型产生不同的函数
templatebool mycompare(T& a,T& b) { if(a==b) return true; } template<> bool mycompare(Person& a,Person& b) { if(a.name==b.name && a.age==b.age) return true; else return false; } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 a = bIII.编译器会对函数模板进行再次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译。
1.1.4 类模板
1.声明
templateclass Person { public: Person(NAMETYPE name,AGETYPE age) { this->name = name; this->age = age; } void showperson() { cout << "name is : " << this->name << endl; cout << "age is : " << this->age << endl; } NAMETYPE name; AGETYPE age; }; 我们可以有多种模板声明,函数模板也可以。
2.调用
I.自动类型推导:类模板不可以用(对比于函数模板)
Person p1("sunwukong",100);这是错误的,在函数模板可以用在类模板不可以用。
II.指定类型
void test01() { Personp1("sunwukong",100); p1.showperson(); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 name is : sunwukong age is : 100
3.类模板中成员函数创建时机
class Person1 { public: void showperson1() { cout << "personshow1 is running" << endl; } }; class Person2 { public: void showperson2() { cout << "personshow2 is running" << endl; } }; templateclass Myclass { public: void Func1() { obj.showperson1(); } void Func2() { obj.showperson2(); } T obj; }; void test01() { Myclass p1; p1.Func1(); //p1.Func2(); Myclass p2; //p2.Func1(); p2.Func2(); } 我们可以看到,p1调用不了Func2,p2调用不了Func1。
类模板中成员函数并不是一开始创建的,创建时机是在运行阶段确定出T的类型才创建的。
4.类模板做函数参数
I.指定传入类型
templateclass Person { public: Person(T1 name,T2 age) { this->name = name; this->age = age; } void showperson() { cout << "name is : " << this->name << endl; cout << "age is : " << this->age << endl; } T1 name; T2 age; }; void dowork(Person &p) { p.showperson(); } void test01() { Person p("sunwukong",99); dowork(p); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 name is : sunwukong age is : 99不用编译器猜,自己提供数据类型
II.参数模板化
templatevoid dowork(Person &p) { p.showperson(); } void test02() { Person p("zhubajie",98); dowork(p); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 name is : zhubajie age is : 98让编译器猜两个数据类型是什么
III.将整个类模板化
templatevoid dowork3(T& p) { p.showperson(); } void test03() { Person p("tangseng",10000); dowork3(p); } /home/lhw/桌面/C++/day8/cmake-build-debug/day8 name is : tangseng age is : 10000让编译器猜是哪个类
5.类模板遇到继承及解决
I.必须要指定出父类中T的类型,才能给子类分配内存
templateclass Base { public: T m_a; }; class son : public Base { }; II.更灵活的方式
templateclass Base { public: T m_a; }; template class son : public Base { public: T1 m_b; }; void test04() { son s; } //m_a double m_b int
6.类模板的成员函数类外实现
templateclass Person { public: Person(T1 name,T2 age); void showperson(); T1 name; T2 age; }; template Person ::Person(T1 name,T2 age) { this->name = name; this->age = age; } template void Person :: showperson() { cout << "name is : " << this->name << endl; cout << "age is : " << this->age << endl; }
7.类模板的分文件编写问题及解决
I.头文件.hpp
// // Created by lhw on 2022/6/10. // #ifndef DAY8_PERSON_H #define DAY8_PERSON_H #includeusing namespace std; template class Person { public: Person(T1 name,T2 age); void showperson(); T1 name; T2 age; }; template Person ::Person(T1 name,T2 age) { this->name = name; this->age = age; } template void Person :: showperson() { cout << "name is : " << this->name << endl; cout << "age is : " << this->age << endl; } #endif //DAY8_PERSON_H II.源文件 main.cpp
#include#include "person.hpp" void dowork(Person &p) { p.showperson(); } void test01() { Person p("sunwukong",99); dowork(p); } int main() { test01(); return 0; }
8.类模板碰到友元函数及其解决
I.友元函数类内实现
templateclass Person { public: friend void printperson(Person &p) { cout << "name is : " << p.name << "age is : " << p.age; } public: Person(T1 name,T2 age) { this->name = name; this->age = age; } private: T1 name; T2 age; }; void test03() { Person p("tom",100); printperson(p); } int main() { test03(); return 0; } 可以当作全局函数去调用。
II.友元函数类外实现1:有点复杂
templateclass Person; template void printperson(Person &p); template class Person { public: friend void printperson<>(Person &p); public: Person(T1 name,T2 age) { this->name = name; this->age = age; } private: T1 name; T2 age; }; template void printperson(Person &p) { cout << "name is : " << p.name << "age is : " << p.age; } void test03() { Person p("tom",100); printperson(p); } III.友元函数类外实现2
templateclass Person; template void printperson2(Person &p) { cout << "name is : " << p.name << "age is : " << p.age; } template class Person { public: friend void printperson2<>(Person &p); public: Person(T1 name,T2 age) { this->name = name; this->age = age; } private: T1 name; T2 age; }; void test03() { Person p("tom",100); printperson2(p); }
1.1.5 案例:myarray
1.myarray.hpp
// // Created by lhw on 2022/6/10. // #ifndef DAY8_MYARRAY_HPP #define DAY8_MYARRAY_HPP templateclass Myarray { public: Myarray() { } Myarray(int capacity) { this -> capacity = capacity; this -> size = 0; this -> pAddress = new T[this->capacity]; } Myarray(const Myarray & myarray) { this -> capacity = myarray.capacity; this -> size = myarray.size; this -> pAddress = new T[this->capacity]; for (int i = 0 ; i pAddress[i] = myarray.pAddress[i]; } } Myarray& operator=(const Myarray & myarray) { if(this->pAddress) { delete []this->pAddress; this -> pAddress = NULL; } this -> capacity = myarray.capacity; this -> size = myarray.size; this -> pAddress = new T[this->capacity]; for (int i = 0 ; i pAddress[i] = myarray.pAddress[i]; } return *this; } ~Myarray() { if(this->pAddress) { delete []this->pAddress; this -> pAddress = NULL; } } T& operator[](int index) { return this->pAddress[index]; } void pushback(const T & value) { if(this -> capacity == this -> size) { return; } this -> pAddress[this->size] = value; this ->size ++; } int getCapacity() { return this->capacity; } int getSize() { return this->size; } private: T * pAddress; int capacity; int size; }; #endif //DAY8_MYARRAY_HPP
2.main.cpp
#include#include using namespace std; #include "myarray.hpp" class Person { public: Person(){}; Person(string name,int age) { this -> name = name; this -> age = age; } public: string name; int age; }; void myprintint(Myarray & myarray) { for(int i=0;i myintarray(100); for(int i = 0;i<10;i++) { myintarray.pushback(i+100); } myprintint(myintarray); } void myprintPerson(Myarray & perArr) { for(int i =0 ; i myPersonarray(100); Person p1("sunwukong",10); Person p2("zhubajie",20); Person p3("tangseng",30); myPersonarray.pushback(p1); myPersonarray.pushback(p2); myPersonarray.pushback(p3); myprintPerson(myPersonarray); cout << "capacity is " << myPersonarray.getCapacity() << endl; cout << "size is " << myPersonarray.getSize() << endl; } int main() { test01(); test02(); return 0; }
3.结果
/home/lhw/桌面/C++/day8/cmake-build-debug/day8 100 101 102 103 104 105 106 107 108 109 name is : sunwukong age is : 10 name is : zhubajie age is : 20 name is : tangseng age is : 30 capacity is 100 size is 3



