白骑士的C++教学进阶篇 2.3 模板

19 篇文章 0 订阅

系列目录

上一篇:白骑士的C++教学进阶篇 2.2 面向对象编程(OOP)

        模板是C++中一个强大的特性,允许编写通用的代码,提高代码的重用性和灵活性。模板分为函数模板和类模板,还包括模板特化。本篇博客将详细介绍这些内容,帮助您深入理解和应用模板编程。

函数模板

        函数模板允许定义通用的函数,不依赖具体的数据类型。通过参数化类型,函数模板可以用于不同类型的参数。

函数模板的定义与使用

        定义一个函数模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的交换函数:

template <typename T>
void swap(T& a, T& b) {
    T temp = a;
    a = b;
    b = temp;
}

        在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用函数模板交换两个整数和两个字符串,代码如下:

int main() {
    int x = 10, y = 20;

    swap(x, y);

    std::cout << "x: " << x << ", y: " << y << std::endl;
    std::string str1 = "Hello", str2 = "World";

    swap(str1, str2);

    std::cout << "str1: " << str1 << ", str2: " << str2 << std::endl;

    return 0;
}

        在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的交换功能。

多个模板参数

        函数模板可以有多个模板参数。例如,定义一个比较函数,返回较大的值:

template <typename T1, typename T2>


auto max(T1 a, T2 b) -> decltype(a > b ? a : b) {

    return a > b ? a : b;
}

        使用该模板函数比较不同类型的值,例如:

int main() {
    int a = 10;
    double b = 20.5;

    std::cout << "Max: " << max(a, b) << std::endl;

    char c = 'A';

    std::cout << "Max: " << max(a, c) << std::endl;

    return 0;
}

        在上面的代码中,模板参数 ‘T1‘ 和 ‘T2‘ 分别被推导为 ‘int‘ 和 ‘double‘,实现了通用的比较功能。

类模板

        类模板允许定义通用的类,不依赖具体的数据类型。通过参数化类型,类模板可以用于不同类型的成员变量和方法。

类模板的定义与使用

        定义一个类模板使用 ‘template‘ 关键字和模板参数列表。例如,定义一个通用的数组类:

template <typename T>


class Array {
private:
    T* data;
    int size;


public:
    Array(int s) : size(s) {
        data = new T[size];
    }

    ~Array() {
        delete[] data;
    }

    T& operator[](int index) {
        return data[index];
    }

    int getSize() const {
        return size;
    }
};

        在这个例子中,‘T‘ 是一个模板参数,可以代表任意类型。使用类模板创建整数数组和字符串数组,例如:

int main() {
    Array<int> intArray(5);

    for (int i = 0; i < intArray.getSize(); i++) {
        intArray[i] = i * 10;
    }

    for (int i = 0; i < intArray.getSize(); i++) {
        std::cout << intArray[i] << std::endl;
    }

    Array<std::string> strArray(3);
    strArray[0] = "Hello";
    strArray[1] = "World";
    strArray[2] = "C++";

    for (int i = 0; i < strArray.getSize(); i++) {
        std::cout << strArray[i] << std::endl;
    }

    return 0;
}

        在上面的代码中,模板参数 ‘T‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的数组类。

多个模板参数

        类模板可以有多个模板参数。例如,定义一个键值对类:

template <typename K, typename V>


class KeyValuePair {
private:
    K key;
    V value;

public:
    KeyValuePair(K k, V v) : key(k), value(v) {}

    K getKey() const {
        return key;
    }

    V getValue() const {
        return value;
    }
};

        使用该类模板创建不同类型的键值对,例如:

int main() {
    KeyValuePair<int, std::string> intStrPair(1, "one");

    std::cout << "Key: " << intStrPair.getKey() << ", Value: " << intStrPair.getValue() << std::endl;

    KeyValuePair<std::string, double> strDoublePair("PI", 3.14);

    std::cout << "Key: " << strDoublePair.getKey() << ", Value: " << strDoublePair.getValue() << std::endl;

    return 0;
}

        在上面的代码中,模板参数 ‘K‘ 和 ‘V‘ 分别被推导为 ‘int‘ 和 ‘std::string‘,实现了通用的键值对类。

模板特化

        模板特化允许为特定的数据类型提供特殊的实现。当通用的模板代码不能满足特定类型的需求时,使用模板特化可以提供优化或特定功能的实现。

全特化

        全特化是为特定类型提供完全不同的实现。例如,定义一个打印模板函数,并为 ‘char*‘ 类型提供特化:

template <typename T>


void print(T value) {
    std::cout << "Generic print: " << value << std::endl;
}


template <>


void print<char*>(char* value) {
    std::cout << "Specialized print: " << value << std::endl;
}

        使用模板函数打印不同类型的值,例如:

int main() {
    print(42);
    print(3.14);
    print("Hello, world!");

    return 0;
}

        在上面的代码中,‘print‘ 模板函数为 ‘char*‘ 类型提供了特化,实现了不同的打印功能。

偏特化

        偏特化是为模板的某些参数提供特定的实现,而其他参数仍然使用通用模板。例如,定义一个通用的数组类模板,并为指针类型提供偏特化:

template <typename T>


class Array {
private:
    T* data;
    int size;

public:
    Array(int s) : size(s) {
        data = new T[size];
    }

    ~Array() {
        delete[] data;
    }

    T& operator[](int index) {
        return data[index];
    }

    int getSize() const {
        return size;
    }
};


// 为指针类型提供偏特化
template <typename T>


class Array<T*> {
private:
    T** data;
    int size;

public:
    Array(int s) : size(s) {
        data = new T*[size];

        for (int i = 0; i < size; i++) {
            data[i] = nullptr;
        }
    }

    ~Array() {
        for (int i = 0; i < size; i++) {
            delete data[i];
        }
        delete[] data;
    }

    T*& operator[](int index) {
        return data[index];
    }

    int getSize() const {
        return size;
    }
};

        使用该模板类创建指针数组,例如:

int main() {
    Array<int*> ptrArray(3);
    for (int i = 0; i < ptrArray.getSize(); i++) {
        ptrArray[i] = new int(i * 10);
    }

    for (int i = 0; i < ptrArray.getSize(); i++) {
        std::cout << *ptrArray[i] << std::endl;
    }

    return 0;
}

        在上面的代码中,模板类 ‘Array‘ 为指针类型提供了偏特化,实现了不同的内存管理。

总结

        模板是C++中一个强大的特性,通过函数模板、类模板和模板特化,程序员可以编写通用、高效的代码,提高代码的重用性和灵活性。理解并熟练掌握模板编程,将大大提高您的编程能力和效率。希望通过本篇博客的介绍,您能更好地理解和应用C++模板,为编写复杂和高效的C++程序打下坚实的基础。

下一篇:白骑士的C++教学进阶篇 2.4 标准模板库(STL)​​​​​​​

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

白骑士所长

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

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

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

打赏作者

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

抵扣说明:

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

余额充值