04 泛型编程
1、概论
编程范式:面向过程编程、面向对象编程、泛型编程。
泛型编程:目的是编写能够适合多种数据类型的代码,而不是为每种特定的数据类型编写重复的代码。
模板是实现泛型的主要工具,主要分为函数模板和类模板。
函数模板:
T代表了任意类型。
类模板:
ATL是泛型编程的典型应用。
2、函数模板
2.1 定义和调用
#include <iostream>
using namespace std;
// 函数模板
/*
template<typename T>
函数的定义
*/
int addInt(int a, int b) {
int c = a + b;
return c;
}
double addDouble(double a, double b) {
double c = a + b;
return c;
}
//提取“公因式”
template<typename T>//加之后 T就可用
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
int c = addInt(a, b);
cout << c << endl;//3
double aa = 1.1, bb = 1.91;
double cc = addDouble(aa, bb);
cout << cc << endl;//3.01
c = add(a, b);//自动类型的推导
cout << c << endl;//3
cc = add(aa, bb);
cout << cc << endl;//3.01
//显示指定类型
c=add<int>(a, b);
cout << c << endl;
cc = add<double>(aa, bb);
cout << cc << endl;//3.01
int n = add<char>('a', 'b');
cout<<n <<endl;//值为-61?
return 0;
}
2.2 与普通函数的区别
#include <iostream>
using namespace std;
int addInt(int a, int b) {
int c = a + b;
return c;
}
double addDouble(double a, double b) {
double c = a + b;
return c;
}
//
template<typename T>
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
double d = 2.1;
double c = addDouble(a, b);//隐式类型转换,a/b转换为double
cout << c << endl;
//int c = add(a, d); 错误: d是double 所以 T变成int又变成double 不可以
//cout << c << endl; //自动类型推导无隐式类型转换
// 函数模板的 【显式指定类型】 调用时的 【隐式类型转换】
int c1 = add<int>(a, d);
c1 = add<double>(a, d);
return 0;
}
2.3与普通函数的调用规则
#include <iostream>
using namespace std;
int add(int a, int b) {
cout << "调用普通函数" << endl;
return a + b;
}
template<typename T>
T add(T a, T b) {
cout << "调用函数模板" << endl;
return a + b;
}
int main() {
int a = 1, b = 2;
add(a, b);//优先调用普通函数
//输出:调用普通函数
add<int>(a, b);//调用函数模板
add<>(a, b);
return 0;
}
函数模板的优先调用:
#include <iostream>
using namespace std;
int add(int a, int b) {
cout << "调用普通函数" << endl;
int c = a + b;
return c;
}
template<typename T>
T add(T a, T b) {
cout << "调用函数模板" << endl;
T c = a + b;
return c;
}
int main() {
double a = 1, b = 2;
add(a, b);//普通函数未完美匹配,编译器选择函数模板
return 0;
}
2.4 多参数函数被模板
#include <iostream>
using namespace std;
//template<typename T1, typename T2, typename T3>
//T1 add(T2 a, T3 b) {
// cout << typeid(T2).name() << endl;//返回值类型无法作为推导依据
// cout << typeid(T3).name() << endl;
// T1 c = a + b;
// return c;
//}
template<typename T2, typename T3>
T2 add(T2 a, T3 b) {
cout << typeid(T2).name() << endl;//类型? float
cout << typeid(T3).name() << endl;//__int64
T2 c = a + b;
return c;
}
int main() {
double r = add(4.0f, 8881281881);
return 0;
}
/*
1、函数模板支持多个类型参数
2、一旦有类型不能推导,就会导致编译失败
3、返回值类型无法作为推导依据
*/
3、类模板
3.1 动态数组类
#include <iostream>
using namespace std;
class DynamicArray {
private:
int* elements;
int size;
public:
DynamicArray(int n) : size(n) {
elements = new int[n];//动态内存申请
}
~DynamicArray() {
delete[] elements;//会导致内存泄露,所以要销毁
}
int& operator[](int index) { //[]的运算符重载
return elements[index]; //返回引用,才可以赋值
}
};
int main() {
int n = 10;
// int a[n];错误
int* p = new int[n];//实现
DynamicArray da(100);
da[1] = 3;//运算符重载
da[9] = 4;
cout << da[0] << ' ' << da[1] << endl;//-842150451 3
return 0;
}
3.2 类模板的定义
#include <iostream>
using namespace std;
//template<typename T>都可以
template<class T>
class DynamicArray {
private:
T* elements;
int size;
public:
DynamicArray(int n) : size(n) {
elements = new T[size];
}
~DynamicArray() {
delete[] elements;
}
T& operator[](int index) {
return elements[index];
}
};
int main() {
//int n = 10;
//int a[n];
//int* p = new int[n];
//实现类模板,代码的复用
DynamicArray<double> da(100);//类模板实例化
da[1] = 3.1;
da[9] = 4.2;
cout << da[0] << ' ' << da[9] << endl;//-6.27744e+66 4.2
DynamicArray<char> dac(10);
dac[0] = 'A';
dac[1] = 'C';
dac[2] = 'M';
cout << dac[0] << dac[1] << dac[2] << endl;//ACM
return 0;
}
3.3 成员函数
类内定义:
#include <iostream>
using namespace std;
template<class T>
class DynamicArray {
private:
T* elements;
int size;
public:
DynamicArray(int n) ; size(n) {
elements = new T[n];
}
~DynamicArray() {
delete[] elements;
}
T& operator[](int index) { //
return elements[index];
}
// 更新第 index 个索引的元素,把它的值改成 value
void update(int index, T value) { //类模板的成员函数
elements[index] = value;
}
};
int main() {
DynamicArray<char> dac(100);
dac[56] = 'h';
dac.update(56, 'u');
cout << dac[56] << endl;//u
return 0;
}
类外定义:
#include <iostream>
using namespace std;
template<class T>
class DynamicArray {
private:
T* elements;
int size;
public:
DynamicArray(int n);
~DynamicArray();
T& operator[](int index);
void update(int index, T value);// 更新第 index 个索引的元素,把它的值改成 value
};
//类外定义成员函数
template<class T>//必加
DynamicArray<T>::DynamicArray(int n):size(n) {
elements = new T[n];
}
template<class T>//必加
DynamicArray<T>::~DynamicArray(){
delete[] elements;
}
template<class T>//必加
T& DynamicArray<T>::operator[](int index) { //
return elements[index];
}
template<class T>//必加
void DynamicArray<T>::update(int index, T value) { //类模板的成员函数
elements[index] = value;
}
int main() {
DynamicArray<char> dac(100);
dac[56] = 'h';
dac.update(56, 'u');
cout << dac[56] << endl;//u
return 0;
}
创建时机:
#include <iostream>
using namespace std;
class Player {
public:
void run() {
cout << "跑步" << endl;
}
};
class Ball {
public:
void drop() {
cout << "下落" << endl;
}
};
template<class T>//类模板
class Test {
T obj;
public:
void move1() {//普通成员是在一开始就创建了,但类模板的
obj.run();//成员函数会在调用时才创建
}
void move2() {
obj.drop();
}
};
int main() {
Test<Player> test1;
test1.move1();
//test1.move2()"drop": 不是 "Player" 的成员 类模板
Test<Ball> test2;
// test2.move1();
test2.move2();
return 0;
}
3.4 类模板对象的函数传参
#include <iostream>
using namespace std;
template<class NameType, class HpType>
class Hero {
public:
Hero(NameType name, HpType hp) {
this->m_name = name;
this->m_hp = hp;
}
private:
NameType m_name;
HpType m_hp;
};
// 1、直接指定类型
void test1(Hero<string, double>& h) {
}
// 2、参数模板化
template<typename T1, typename T2>
void test2(Hero<T1, T2>& h) {
}
// 3、类模板化
template<typename T>
void test3(T& h) {
}
int main() {
Hero<string, double> h("宋江", 100.0);
test1(h);
test2(h);
test3(h);
return 0;
}
3.5继承
#include <iostream>
using namespace std;
template<class NameType, class HpType>
class Hero {
public:
Hero(NameType name, HpType hp) {
this->m_name = name;
this->m_hp = hp;
}
private:
NameType m_name;
HpType m_hp;
};
template<class T1, class T2, class T3>
class HeroSon : public Hero<T1, T2> {
T3 a;
};
int main() {
return 0;
}