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 类模板,并演示了添加元素、获取元素以及获取数组大小的操作。
通过这个案例,我们可以看到类模板的通用性和灵活性。它使我们能够使用相同的代码定义不同类型的动态数组,从而提供了代码重用和泛型编程的好处。