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://hbruida.cn/article/gopcg.html