C++模板初阶(新手入门必看!)


1. 泛型编程

泛型编程(Generic Programming)是一种编程范式,它允许程序员编写与数据类型无关的代码。通过使用泛型,程序员可以编写灵活、可重用的函数、类或数据结构,这些函数、类或数据结构可以操作多种类型的数据,而无需为每种数据类型编写单独的代码。泛型编程的核心思想是将算法与数据类型分离,使得算法可以独立于数据类型之外进行编写和测试。

特点

  1. 类型安全:泛型编程在编译时就能检查类型错误,避免了运行时错误。
  2. 代码复用:通过编写与数据类型无关的代码,可以极大地提高代码的复用性。
  3. 性能优化:由于泛型代码在编译时就已经确定了类型,因此编译器可以对代码进行优化,提高运行效率。
  4. 清晰易读:使用泛型可以使代码更加清晰、简洁,易于理解和维护。

泛型编程的实现

  • C++通过模板(Templates)来实现泛型编程。模板允许程序员定义与类型无关的函数、类或数据结构,然后在编译时根据具体的类型生成相应的代码。

示例

下面是一个简单的泛型函数示例,该函数用于交换两个变量的值:

template<typename T>  
void swap(T& a, T& b) {  
    T temp = a;  
    a = b;  
    b = temp;  
}  
  
int main() {  
    int x = 1, y = 2;  
    swap(x, y); // 调用模板函数,T被推导为int  
  
    double a = 3.14, b = 2.71;  
    swap(a, b); // 调用模板函数,T被推导为double  
  
    return 0;  
}

在这个例子中,swap函数是一个模板函数,它接受两个类型为T的参数(T是一个占位符,代表任意类型)。在main函数中,我们分别用intdouble类型的变量调用了swap函数,编译器会根据调用时的实际类型自动推导T的类型,并生成相应的代码。

2. 函数模板

函数模板是C++中泛型编程的一种实现方式,它允许你定义一个与类型无关的函数。通过使用模板参数,你可以编写一个函数模板,该函数模板可以处理多种类型的数据,而无需为每种数据类型都编写一个单独的函数。

函数模板的定义使用template关键字开始,后跟一个或多个模板参数(这些参数通常被放在尖括号<>中),最后是函数返回类型、函数名和参数列表。模板参数可以是类型参数(如typename Tclass T),也可以是非类型参数(如int N),但在函数模板中,最常见的是类型参数。

函数模板的基本语法

template<typename T> // 或 template<class T>,两者在函数模板中几乎等价  
返回类型 函数名(参数列表) {  
    // 函数体  
}

【示例】

以下是一个简单的函数模板示例,用于计算两个值的最大值:

#include <iostream>  
  
template<typename T>  
T max(T a, T b) {  
    return (a > b) ? a : b;  
}  
  
int main() {  
    std::cout << "The max of 5 and 3 is " << max(5, 3) << std::endl;  
    std::cout << "The max of 5.5 and 4.2 is " << max(5.5, 4.2) << std::endl;  
  
    // 注意:以下调用将引发编译错误,因为max(5, 3.14)的参数类型不同  
    // std::cout << "The max of 5 and 3.14 is " << max(5, 3.14) << std::endl;  
  
    return 0;  
}

在这个例子中,max函数模板接受两个类型为T的参数,并返回这两个参数中较大的一个。在main函数中,我们分别用intdouble类型的参数调用了max函数模板,编译器根据调用时的实际类型自动推导T的类型,并生成相应的函数实例。

【 模板参数推导】

在调用函数模板时,编译器会自动推导模板参数的类型。这个过程通常基于函数实参的类型进行。如果编译器无法从函数实参中唯一地推导出模板参数的类型,或者推导出的类型不符合模板参数的要求(比如,模板参数有约束),则会导致编译错误。

模板的特化和重载

  • 模板特化:允许你为特定的类型提供模板的定制版本。这在你需要为特定类型优化模板实现时非常有用。
  • 模板重载:与函数重载类似,你可以定义多个模板函数,只要它们的模板参数列表或函数参数列表不同即可。

通过结合使用函数模板、模板特化和模板重载,你可以创建出既灵活又高效的代码,以适应不同的数据类型和场景。

3. 类模板

类模板是C++中泛型编程的另一种重要方式,它允许你定义与类型无关的类。与函数模板类似,类模板使用template关键字后跟模板参数列表来定义。这些模板参数通常是类型参数,但也可以是非类型参数(如整数常量)。类模板可以在类定义中使用这些模板参数来指定成员变量的类型或成员函数的返回类型、参数类型等。

类模板的基本语法

template<typename T, typename U> // 可以有多个模板参数  
class ClassName {  
public:  
    T memberVar; // 成员变量使用模板参数类型  
    U anotherMemberVar;  
  
    ClassName(T val1, U val2); // 构造函数  
  
    // 其他成员函数  
    void someFunction(T param);  
};  
  
// 构造函数的实现  
template<typename T, typename U>  
ClassName<T, U>::ClassName(T val1, U val2) : memberVar(val1), anotherMemberVar(val2) {  
    // 构造函数体  
}  
  
// 成员函数的实现  
template<typename T, typename U>  
void ClassName<T, U>::someFunction(T param) {  
    // 函数体  
}

以下是一个简单的类模板示例,用于创建一个简单的栈容器:

#include <iostream>  
  
template<typename T>  
class Stack {  
private:  
    T* elements;  
    size_t top;  
    size_t capacity;  
  
public:  
    Stack(size_t capacity) : top(0), capacity(capacity) {  
        elements = new T[capacity];  
    }  
  
    ~Stack() {  
        delete[] elements;  
    }  
  
    void push(const T& element) {  
        if (top < capacity) {  
            elements[top++] = element;  
        } else {  
            std::cerr << "Stack overflow!" << std::endl;  
        }  
    }  
  
    T pop() {  
        if (top > 0) {  
            return elements[--top];  
        } else {  
            std::cerr << "Stack underflow!" << std::endl;  
            // 注意:这里需要返回某种默认值或抛出异常,具体取决于你的需求  
            return T(); // 返回T类型的默认值  
        }  
    }  
  
    bool isEmpty() const {  
        return top == 0;  
    }  
  
    // 其他成员函数...  
};  
  
int main() {  
    Stack<int> intStack(10);  
    intStack.push(1);  
    intStack.push(2);  
    std::cout << "Popped: " << intStack.pop() << std::endl;  
  
    Stack<std::string> stringStack(5);  
    stringStack.push("Hello");  
    stringStack.push("World");  
    std::cout << "Popped: " << stringStack.pop() << std::endl;  
  
    return 0;  
}

在这个例子中,我们定义了一个名为Stack的类模板,它接受一个类型参数T,用于指定栈中存储的元素的类型。然后,我们在main函数中分别创建了一个int类型的栈和一个std::string类型的栈,并展示了如何使用它们。

【模板特化】

类模板特化允许你为特定的类型提供类的定制版本。这在你需要为某些类型提供特殊的实现或优化时非常有用。特化可以是完全特化(指定所有模板参数的类型)或偏特化(只指定部分模板参数的类型)。

【模板实例化】

当你使用类模板时,编译器会根据你提供的类型参数生成类的具体实例。这个过程称为模板实例化。在上面的例子中,Stack<int>Stack<std::string>就是Stack类模板的两个实例化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值