当前位置: 首页 > news >正文

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

相关文章:

  • AMBA-CHI协议详解(二十四)
  • window.btoa 和 atob 记不住,怎么根据字母意思去理解
  • 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序
  • 当底层硬盘老旧时,如何限制Linux服务器和Windows服务的IOPS?
  • 苍穹外卖-Spring Task使用的前置条件
  • GROOT N1,英伟达开源的人形机器人模型
  • 【LLMs篇】06:Encoder-Only vs Decoder-Only vs Encoder-Decoder
  • OWASP Top 10 解读:如何构建更安全的应用?
  • 【C++】二叉树和堆的链式结构
  • 阿里云 AI 搜索产品荣获 Elastic Innovation Award 2024
  • MySQL 调优
  • 线性规划的标准形式
  • openpnp - 如果安装面的钣金接触面不平,可以尝试加垫片
  • Springboot List集合的校验方式
  • 替代Qt中信号与槽的完整例子。
  • CVPR2025 | TAPT:用于视觉语言模型鲁棒推理的测试时对抗提示调整
  • 如何实现一个DNS
  • Java Web应用程序实现用户登录、学生信息管理和验证码验证以及页面跳转等基本功能(IDEA)含(Ajax、JSTL)
  • 【时时三省】(C语言基础)用gutchar函数输入一个字符
  • Session 、Cookies 和 Token关系于区别
  • 五大光伏龙头一季度亏损超80亿元,行业冬天难言结束
  • 视频丨中国海警位中国黄岩岛领海及周边区域执法巡查
  • 新希望一季度归母净利润4.45亿,上年同期为-19.34亿
  • 媒体:黑话烂梗包围小学生,“有话好好说”很难吗?
  • 昆明破获一起算命破灾诈骗案,民警:大师算不到自己的未来
  • 影子调查丨危房之下,百余住户搬离梦嘉商贸楼