目录
模板
模板的特点
函数模板
前言
函数模板的使用方式
函数模板具体案例
使用模板的注意事项
普通函数与函数模板间的区别
具体案例
普通函数与函数模板调用规则
模板的局限性
具体化模板
类模板
前言
类模板与函数模板的区别
类模板中成员函数创建时机
类模板对象做函数的参数
传入方式
具体案例
类模板与继承
前言
子类指定具体类型案例
子类不指定具体类型案例
类模板成员函数的类外实现
类模板分文件编写
1.直接包含源文件
2.将.h和.cpp文件中的内容写到一起,后将后缀名改为.hpp文件
类模板与友元
前言:
概念:模板就是建立通用的模具,大大提高复用性
使用模板的目的:提高复用性,将类型参数化
作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法:
//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
template
函数声明或函数定义
解释:
#define _CRT_SECURE_NO_WARNINGS 1
#include
using namespace std;
//函数模板
template
//通用交换函数模板
void mySwap(T& a, T& b) {T temp = a;a = b;b = temp;
}
void main() {int a = 10;int b = 20.0;//自动类型推导(a和b的数据类型会被自动解析)mySwap(a, b);cout << "a:" << a << "\tb:" << b << endl;//显式指定类型(为模板参数)mySwap(a,b);cout << "a:" << a << "\tb:" << b << endl;
}
普通函数调用时可以发生自动类型转换(隐式类型转换);函数模板调用时,若利用自动类型推导,则不会发生隐式类型转换,但若利用显式指定类型的方式则可以发生隐式类型转换
#include
using namespace std;
template
T myAdd(T a, T b) {return a + b;
}
void main() {int a = 10;char c = 'c';//自动类型推导//cout << myAdd(a, c) << endl;//报错,参数类型的指定必须一致,不能自动类型转换//隐式指定类型cout << myAdd(a, c) << endl;//明确说明T的类型为int,传入的参数是int类型直接传,不是int类型则使用隐式类型转换转为int类型
}
1.若函数模板与普通函数都可以调用,则优先调用普通函数
void myPrint(int a, int b) {cout << "调用普通函数" << endl;
}
template
void myPrint(T a, T b) {cout << "调用函数模板" << endl;
}
void main() {int a = 10;int b = 20;myPrint(a, b);//调用普通函数
}
2.可以通过空模板参数列表的方式来强制调用函数模板
//只写了函数声明,没写函数实现
void myPrint(int a, int b);
template
void myPrint(T a, T b) {cout << "调用函数模板" << endl;
}
void main() {int a = 10;int b = 20;//通过空模板的参数列表强制调用函数模板myPrint<>(a, b);
}
3.模板也可以实现函数重载
template
void myPrint(T a, T b) {cout << "调用函数模板1" << endl;
}
//重载函数模板
template
void myPrint(T a, T b, T c) {cout << "调用函数模板2" << endl;
}
void main() {int a = 10;int b = 20;int c = 30;//调用函数模板1myPrint(a, b);//调用函数模板2myPrint(a, b, c);
}
4.如果函数模板可以产生更好的匹配,则优先使用函数模板
void myPrint(int a, int b) {cout << "调用普通函数" << endl;
}
template
void myPrint(T a, T b) {cout << "调用函数模板" << endl;
}
void main() {char a = 'a';char b = 'b';//调用函数模板myPrint(a, b);
}
注意:若提供了函数模板,那么最好就不要提供普通函数,否则容易出现二义性
template
void func(T a, T b) {a = b;
}
注意:模板并不是万能的,该模板函数有一个局限性,若传入的a和b是一个数组,那么就无法实现了
class Person {
public:Person(string name, int age) {this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};
template
bool myCompare(T& a, T& b) {if (a == b) {return true;}else {return false;}
}
//利用具体化(template<>)的Person版本来实现代码,具体化优先调用
template<> bool myCompare(Person & a, Person & b) {if (a.m_Age == b.m_Age && a.m_Name == b.m_Name) {return true;}else {return false;}
}
void main() {Person p1("Tom", 10);Person p2("Tom", 10);bool ret = myCompare(p1, p2);if (ret) {cout << "p1==p2" << endl;}else {cout << "p1!=p2" << endl;}
}
解释:模板的类型若为Person类型,那么自动调用具体化了的方法
作用:建立一个通用的类,类中的成员,数据类型可以不具体指定,用一个虚拟的类型来代表
语法:
template
类
解释:
1.类模板没有自动类型推导的使用方式
template
class Person {
public:Person(NameType name, AgeType age) {this->m_Name = name;this->m_Age = age;}NameType m_Name;AgeType m_Age;
};
void main() {//类模板的使用(显式指定类型)Person p("叶秋", 25);cout << "p的name:" << p.m_Name << endl << "p的age:" << p.m_Age << endl;
}
2.类模板在模板参数列表中可以有默认参数
//int为类模板的默认参数
template
class Person {
public:Person(NameType name, AgeType age) {this->m_Name = name;this->m_Age = age;}NameType m_Name;AgeType m_Age;
};
void main() {//类模板默认参数的使用Person p("叶秋", 25);cout << "p的name:" << p.m_Name << endl << "p的age:" << p.m_Age << endl;
}
template
class Person {
public:Person(NameType name, AgeType age) {this->m_Name = name;this->m_Age = age;}void showPerson() {cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;}NameType m_Name;AgeType m_Age;
};
//指定传入类型
void printPerson1(Person &p) {p.showPerson();
}
//参数模板化
template
void printPerson2(Person &p) {p.showPerson();
}
//整个类模板化
template
void printPerson3(P &p) {p.showPerson();
}
void main() {Person p("孙悟空", 100);printPerson1(p);printPerson2(p);printPerson3(p);
}
template
class Base {T m;
};
class Son:public Base {};
template
class Base {T m;
};
template
class Son:public Base {};
template
class Person {
public:Person(NameType name, AgeType age);void showPerson();NameType m_Name;AgeType m_Age;
};
//构造函数的类外实现
template
Person::Person(NameType name,AgeType age){this->m_Name = name;this->m_Age = age;
}
//成员函数的类外实现
template
void Person::showPerson() {cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
注意:类模板中的成员函数类外实现时需要加上模板的参数列表
person.h文件内
#pragma once
#include
using namespace std;
template
class Person {
public:Person(NameType name, AgeType age);void showPerson();NameType m_Name;AgeType m_Age;
};
person.cpp文件内
#include "person.h"
//构造函数的类外实现
template
Person::Person(NameType name, AgeType age) {this->m_Name = name;this->m_Age = age;
}
//成员函数的类外实现
template
void Person::showPerson() {cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
执行文件内
//这里必须包含.cpp文件方可
#include "person.cpp"
void main() {Person p("lili", 18);p.showPerson();
}
执行文件不可以包含.h文件必须包含.cpp问件原因:类模板中的成员函数在调用时才可以创建
person.hpp文件内
#pragma once
#include
using namespace std;
template
class Person {
public:Person(NameType name, AgeType age);void showPerson();NameType m_Name;AgeType m_Age;
};//构造函数的类外实现
template
Person::Person(NameType name, AgeType age) {this->m_Name = name;this->m_Age = age;
}
//成员函数的类外实现
template
void Person::showPerson() {cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
执行文件内
//这里必须包含.hpp文件
#include "person.hpp"
void main() {Person p("lili", 18);p.showPerson();
}
1.全局函数类内实现,直接在类内声明友元即可
template
class Person {//全局函数类内实现friend void printPerson(Person p) {cout << "姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;}
public:Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;}
private:T1 m_Name;T2 m_Age;
};
void main() {Person p("lili", 18);printPerson(p);
}
2.全局函数类外实现,需要让编译器知道该全局函数的存在
//编译器需要先知道printPerson函数的存在以及Person类的存在
template< class T1, class T2 >
class Person;
template
void printPerson(Person< T1, T2 > p) {cout << "姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;
}
template
class Person {//全局函数类外实现//加空模板参数列表证明他是个模板函数//若全局函数是类外实现,需要让编译器提前知道这个函数的存在friend void printPerson<>(Person p);
public:Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;}
private:T1 m_Name;T2 m_Age;
};
void main() {Person p("lili", 18);printPerson(p);
}