C++之泛型编程-创新互联
目录
模板
模板的特点
函数模板
前言
函数模板的使用方式
函数模板具体案例
使用模板的注意事项
普通函数与函数模板间的区别
具体案例
普通函数与函数模板调用规则
模板的局限性
具体化模板
类模板
前言
类模板与函数模板的区别
类模板中成员函数创建时机
类模板对象做函数的参数
传入方式
具体案例
类模板与继承
前言
子类指定具体类型案例
子类不指定具体类型案例
类模板成员函数的类外实现
类模板分文件编写
1.直接包含源文件
2.将.h和.cpp文件中的内容写到一起,后将后缀名改为.hpp文件
类模板与友元
模板前言:
- C++中相对于面向对象的另一种编程思想就是泛型编程,主要利用的技术就是模板
- C++提供了两种模板机制(函数模板和类模板)
概念:模板就是建立通用的模具,大大提高复用性
模板的特点- 模板不可以直接使用,它只是一个框架
- 模板通用性很强,但是并不是万能的
使用模板的目的:提高复用性,将类型参数化
函数模板 前言作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法:
//声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用的数据类型
template函数声明或函数定义
解释:
- template:声明创建模板
- typename:表明其后面的符号为一种数据类型(该关键字也可以用class代替)
- T:通用的数据类型;名称可以替换,通常为大写字母。
- 自动类型推导:向交换模板函数中传递的参数的类型会被自动解析
- 显示指定类型:指定模板的具体数据类型
#define _CRT_SECURE_NO_WARNINGS 1
#includeusing 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;
}
使用模板的注意事项- 在函数中,若多个参数使用模板,那么自动类型推导必须推导出一致的数据类型才可以使用
- 模板必须确定出T的数据类型才可以使用
普通函数调用时可以发生自动类型转换(隐式类型转换);函数模板调用时,若利用自动类型推导,则不会发生隐式类型转换,但若利用显式指定类型的方式则可以发生隐式类型转换
具体案例#includeusing namespace std;
templateT 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;
}
templatevoid 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);
templatevoid myPrint(T a, T b) {
cout<< "调用函数模板"<< endl;
}
void main() {
int a = 10;
int b = 20;
//通过空模板的参数列表强制调用函数模板
myPrint<>(a, b);
}
3.模板也可以实现函数重载
templatevoid myPrint(T a, T b) {
cout<< "调用函数模板1"<< endl;
}
//重载函数模板
templatevoid myPrint(T a, T b, T c) {
cout<< "调用函数模板2"<< endl;
}
void main() {
int a = 10;
int b = 20;
int c = 30;
//调用函数模板1
myPrint(a, b);
//调用函数模板2
myPrint(a, b, c);
}
4.如果函数模板可以产生更好的匹配,则优先使用函数模板
void myPrint(int a, int b) {
cout<< "调用普通函数"<< endl;
}
templatevoid myPrint(T a, T b) {
cout<< "调用函数模板"<< endl;
}
void main() {
char a = 'a';
char b = 'b';
//调用函数模板
myPrint(a, b);
}
注意:若提供了函数模板,那么最好就不要提供普通函数,否则容易出现二义性
模板的局限性templatevoid 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;
};
templatebool 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类
解释:
- template:声明创建模板
- typename:表明其后面带符号的是一种数据类型(也可以用class替换)
- T:通用的数据类型,名称可以替换,通常为大写字母
1.类模板没有自动类型推导的使用方式
templateclass Person {
public:
Person(NameType name, AgeType age) {
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
};
void main() {
//类模板的使用(显式指定类型)
Personp("叶秋", 25);
cout<< "p的name:"<< p.m_Name<< endl<< "p的age:"<< p.m_Age<< endl;
}
2.类模板在模板参数列表中可以有默认参数
//int为类模板的默认参数
templateclass Person {
public:
Person(NameType name, AgeType age) {
this->m_Name = name;
this->m_Age = age;
}
NameType m_Name;
AgeType m_Age;
};
void main() {
//类模板默认参数的使用
Personp("叶秋", 25);
cout<< "p的name:"<< p.m_Name<< endl<< "p的age:"<< p.m_Age<< endl;
}
类模板中成员函数创建时机- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才可以创建
- 指定传入类型——直接显示对象的数据类型
- 参数模板化——将对象中的参数变为模板进行传递
- 整个类模板化——将这个对象类型模板化进行传递
templateclass 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();
}
//参数模板化
templatevoid printPerson2(Person&p) {
p.showPerson();
}
//整个类模板化
templatevoid printPerson3(P &p) {
p.showPerson();
}
void main() {
Personp("孙悟空", 100);
printPerson1(p);
printPerson2(p);
printPerson3(p);
}
类模板与继承
前言- 当子类继承的父类是一个类模板时,子类在声明的时候需要指定父类的类型
- 若不指定具体的类型,那么编译器无法给予子类分配内存
- 若想灵活指定父类中T的类型,子类也需要变成类模板
templateclass Base {
T m;
};
class Son:public Base{};
子类不指定具体类型案例templateclass Base {
T m;
};
templateclass Son:public Base{};
类模板成员函数的类外实现templateclass Person {
public:
Person(NameType name, AgeType age);
void showPerson();
NameType m_Name;
AgeType m_Age;
};
//构造函数的类外实现
templatePerson::Person(NameType name,AgeType age){
this->m_Name = name;
this->m_Age = age;
}
//成员函数的类外实现
templatevoid Person::showPerson() {
cout<< "姓名:"<< this->m_Name<< "\t年龄:"<< this->m_Age<< endl;
}
注意:类模板中的成员函数类外实现时需要加上模板的参数列表
类模板分文件编写 1.直接包含源文件person.h文件内
#pragma once
#includeusing namespace std;
templateclass Person {
public:
Person(NameType name, AgeType age);
void showPerson();
NameType m_Name;
AgeType m_Age;
};
person.cpp文件内
#include "person.h"
//构造函数的类外实现
templatePerson::Person(NameType name, AgeType age) {
this->m_Name = name;
this->m_Age = age;
}
//成员函数的类外实现
templatevoid Person::showPerson() {
cout<< "姓名:"<< this->m_Name<< "\t年龄:"<< this->m_Age<< endl;
}
执行文件内
//这里必须包含.cpp文件方可
#include "person.cpp"
void main() {
Personp("lili", 18);
p.showPerson();
}
执行文件不可以包含.h文件必须包含.cpp问件原因:类模板中的成员函数在调用时才可以创建
2.将.h和.cpp文件中的内容写到一起,后将后缀名改为.hpp文件person.hpp文件内
#pragma once
#includeusing namespace std;
templateclass Person {
public:
Person(NameType name, AgeType age);
void showPerson();
NameType m_Name;
AgeType m_Age;
};
//构造函数的类外实现
templatePerson::Person(NameType name, AgeType age) {
this->m_Name = name;
this->m_Age = age;
}
//成员函数的类外实现
templatevoid Person::showPerson() {
cout<< "姓名:"<< this->m_Name<< "\t年龄:"<< this->m_Age<< endl;
}
执行文件内
//这里必须包含.hpp文件
#include "person.hpp"
void main() {
Personp("lili", 18);
p.showPerson();
}
类模板与友元1.全局函数类内实现,直接在类内声明友元即可
templateclass Person {
//全局函数类内实现
friend void printPerson(Personp) {
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() {
Personp("lili", 18);
printPerson(p);
}
2.全局函数类外实现,需要让编译器知道该全局函数的存在
//编译器需要先知道printPerson函数的存在以及Person类的存在
template< class T1, class T2 >class Person;
templatevoid printPerson(Person< T1, T2 >p) {
cout<< "姓名:"<< p.m_Name<< "\t年龄:"<< p.m_Age<< endl;
}
templateclass Person {
//全局函数类外实现
//加空模板参数列表证明他是个模板函数
//若全局函数是类外实现,需要让编译器提前知道这个函数的存在
friend void printPerson<>(Personp);
public:
Person(T1 name, T2 age) {
this->m_Name = name;
this->m_Age = age;
}
private:
T1 m_Name;
T2 m_Age;
};
void main() {
Personp("lili", 18);
printPerson(p);
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
网页名称:C++之泛型编程-创新互联
URL链接:http://scyanting.com/article/gopcg.html