C++快速理解之泛型编程

1、引入

#include <iostream>

using namespace std;

int add(int a, int b) {
    return a + b;
}

float add(float x, float y) {
    return x + y;
}

int main() {

    int result = add(3, 4);
    cout << "result  = " << result << endl;

    float result2 = add(3.5f, 4.5f);
    cout << "result2 = " << result2 << endl;

    return 0;
}

在这里插入图片描述
上述的例子,虽然能够实现计算2个数值的求和计算,但是明显感觉到,代码重复太多了
有没有一种情况使得编码的时候暂时的忽略掉类型这个特性,等运行时在动态决定的呢?

有,泛型

2、泛型编程

是什么?
泛型编程是一种编程范式
它允许在编写代码时使用泛化的数据类型和算法,以增加代码的可重用性和灵活性

怎样做?
在 C++ 中,泛型编程主要通过模板(Templates)来实现
泛型编程的核心思想是编写与特定数据类型无关的代码使代码能够适用于多种数据类型而不需要重复编写
通过使用泛型,可以编写通用的数据结构和算法,使其适用于不同的数据类型,从而提高代码的复用性和扩展性

模板是什么?
模板是一种将类型参数化的工具,可以用来定义通用的类、函数和算法
通过使用模板,可以编写可以适用于多种数据类型的代码

C++ 提供了类模板(Class Templates)和函数模板(Function Templates)来支持泛型编程

template <typename T>
T 函数名(){}

简单的示例,演示了在 C++ 中使用函数模板实现泛型编程:

#include <iostream>

// 函数模板
template <typename T>
T maximum(T a, T b) {
  return (a > b) ? a : b;
}

int main() {
  int intMax = maximum(10, 20); // 调用 maximum 函数,类型推导为 int
  std::cout << "Maximum of 10 and 20 is: " << intMax << std::endl;

  double doubleMax = maximum(3.14, 2.71); // 调用 maximum 函数,类型推导为 double
  std::cout << "Maximum of 3.14 and 2.71 is: " << doubleMax << std::endl;

  return 0;
}

在上述示例中,定义了一个函数模板 maximum,它接受两个类型相同的参数,并返回较大的值。通过使用 typename 和模板参数 T,我们将类型参数化,使函数能够适用于不同的数据类型。
在 main 函数中,我们调用了 maximum 函数两次,一次传递整数参数,一次传递双精度浮点数参数。编译器根据传递的参数类型自动推导出模板参数 T 的具体类型,并生成适当的函数代码。

通过泛型编程,我们可以编写通用的函数模板,能够适应多种数据类型的需求,从而提高代码的复用性和灵活性。泛型编程是 C++ 中强大的特性之一,它使得编写通用、可扩展的代码变得更加容易。

3、函数模板

在 C++ 中,一个函数模板可以对应多个函数。当使用模板生成代码时,编译器会根据传递的参数类型实例化对应的函数

函数模板本身并不是一个具体的函数定义,而是一个通用的模板,用于生成特定类型的函数定义。当编译器在代码中遇到对函数模板的调用时,它会根据传递的参数类型生成具体的函数定义

#include <iostream>

template <typename T>
void printValue(T value) {
    std::cout << "Value: " << value << std::endl;
}

int main() {
    printValue(10);      // 调用 printValue<int>(int)
    printValue(3.14);    // 调用 printValue<double>(double)

    return 0;
}

4、函数模板重载

如普通函数一般,函数模板也可以重载,以便灵活应对更多的需求

#include <iostream>

using namespace std;

template<typename T>
T add(T t1, T t2) {
    T ret;
    ret = t1 + t2;
    return ret;
}

template<typename T>
T add(T t1, T t2, T t3) {
    T ret;
    ret = t1 + t2 + t3;
    return ret;
}

int main() {

    int result1 = add(1, 2);
    int result2 = add(1, 2, 3);

    cout << "result1 = " << result1 << endl;
    cout << "result2 = " << result2 << endl;

    return 0;
}

5、多个参数的函数模板

当需要使用多个参数的函数模板时,可以在模板定义中添加额外的类型参数。这样,实例化函数模板时可以提供多个类型参数,并根据需要进行实例化。

下面是一个示例,演示了一个具有两个类型参数的函数模板的定义和使用:

#include <iostream>

template <typename T, typename U>
void PrintPair(T first, U second) {
    std::cout << "Pair: " << first << ", " << second << std::endl;
}

int main() {
    PrintPair(10, 3.14);                    
    // 实例化函数模板为 PrintPair<int, double>(10, 3.14)
    PrintPair("Hello", std::string("World"));   
    // 实例化函数模板为 PrintPair<const char*, std::string>
    //("Hello", std::string("World"))

    return 0;
}

在上述示例中,我们定义了一个名为 PrintPair 的函数模板,它接受两个类型参数 T 和 U。该函数模板用于打印两个值,分别表示键和值。

在函数模板中,我们使用 T first 和 U second 分别定义了两个函数参数。我们可以像普通函数一样使用这些参数,并在函数体中执行相应的操作。

在 main 函数中,我们使用 PrintPair 函数模板进行调用,并传递不同类型的参数。编译器会根据实际的参数类型实例化函数模板,并生成具体的函数定义。

当然,也可以重载

通过这个案例,我们可以看到如何定义并使用具有多个参数的函数模板。可以根据实际需要提供不同的类型参数,从而创建具有不同类型参数的通用函数。这提供了更大的灵活性和代码重用性。

6、类模板
类模板(Class Template)是 C++ 中用于创建通用类的特性。它允许定义一个模板,其中的类型参数可以在使用时被实例化为具体的类型,从而创建多个具有相似结构和行为的类。

类模板的定义形式如下:

template <typename T>
class ClassName {
    // 类成员和成员函数定义
};

template 表示这是一个类模板,并使用 T 作为类型参数。T 可以是任意合法的标识符,用于表示通用的类型

#include <iostream>

template<typename T>
class DynamicArray {
private:
    T *elements;  // 动态数组的指针
    int size;     // 数组的大小

public:
    DynamicArray(int s) : size(s) {
        elements = new T[size];  // 根据指定大小分配内存
    }

    ~DynamicArray() {
        delete[] elements;  // 释放内存
    }

    void Add(T element) {
        // 添加元素到数组
        // 省略具体的实现逻辑
    }

    T Get(int index) {
        // 获取指定索引处的元素
        // 省略具体的实现逻辑
    }

    int Size() {
        return size;  // 返回数组的大小
    }
};

int main() {
    class DynamicArray<int> intArray(5);           // 创建一个存储整数的动态数组
    class DynamicArray<double> doubleArray(10);    // 创建一个存储双精度浮点数的动态数组

    intArray.Add(10);                        // 向整数数组中添加元素
    doubleArray.Add(3.14);                    // 向双精度浮点数数组中添加元素

    int value = intArray.Get(0);              // 从整数数组中获取元素
    double doubleValue = doubleArray.Get(0);  // 从双精度浮点数数组中获取元素

    std::cout << "Integer array size: " << intArray.Size() << std::endl;
    std::cout << "Double array size: " << doubleArray.Size() << std::endl;

    return 0;
}

在这里插入图片描述
在上述示例中,我们定义了一个名为 DynamicArray 的类模板。它具有一个类型参数 T,用于表示动态数组中的元素类型。

在类模板中,我们使用 T* elements 定义了一个动态数组的指针,并使用 int size 定义了数组的大小。构造函数负责根据指定的大小分配内存,析构函数负责释放内存。

我们还提供了 Add 函数用于向数组中添加元素,Get 函数用于获取指定索引处的元素,Size 函数用于返回数组的大小。

在 main 函数中,我们使用不同的类型实例化了 DynamicArray 类模板,并演示了添加元素、获取元素以及获取数组大小的操作。

通过这个案例,我们可以看到类模板的通用性和灵活性。它使我们能够使用相同的代码定义不同类型的动态数组,从而提供了代码重用和泛型编程的好处。

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

挥剑决浮云 -

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值