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;
}