文章广告位
入驻说明

文章最后更新时间:2024-02-03 09:34:05

第十六章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

模板(Templates)在编程中是一个非常重要的概念,特别是在C++中。它是一种泛型编程的技术,允许程序员定义处理未知数据类型的函数或类。通过使用模板,程序员可以编写处理任意数据类型的代码,而不需要对每种数据类型都重写代码。

模板可以分为函数模板和类模板两种类型。函数模板允许程序员定义一个可以处理不同数据类型的函数,而类模板则允许程序员定义一个可以处理不同数据类型的类。

函数模板的一般形式如下:

template <typename T>  
void functionName(T param) {  
  // 函数体  
}

在这个例子中,T 是一个类型参数,表示函数可以接受任何类型的参数。在函数体中,T 可以被用作任何类型,包括变量声明、返回类型等。

类模板的一般形式如下:

template <typename T>  
class ClassName {  
  // 类体  
};

在这个例子中,T 是一个类型参数,表示类可以包含任何类型的成员变量或函数。在类体中,T 可以被用作任何类型,包括变量声明、返回类型等。

通过使用模板,程序员可以编写更加通用和可复用的代码,提高代码的利用率和可维护性。同时,模板还可以提高代码的安全性,因为类型检查在编译时进行,而不是在运行时进行。

第十六章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

接上一章继续:第十五章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人 – 菜鸟资源 (xiciw.com)

9. 模板(Templates)

泛型(Generic Programming)即是指具有在多种数据类型上皆可操作的含意。泛型编程的代表作品 STL 是一种高效、泛型、可交互操作的软件组件。

泛型编程最初诞生于 C++中,目的是为了实现 C++的 STL(标准模板库)。其语言支持机制就是模板(Templates)。模板的精神其实很简单:参数化类型。换句话说,把一个原本特定于某个类型的算法或类当中的类型信息抽掉,抽出来做成模板参数 T。

9.1. 函数模板

9.1.1. 函数重载实现的泛型

#include <iostream>
using namespace std;
void swap(int &a, int& b)
{
    int t = a;
    a = b;
    b = t;
}
void swap(double &a,double b)
{
    double t = a;
    a = b;
    b = t;
}
int main()
{
    int ia = 10; int ib = 20;
    swap(ia,ib);
    cout<<ia<<ib<<endl;
    double da = 10, db = 20;
    swap(da,db);
    cout<<da<<db<<endl;
    return 0;
}

9.1.2. 函数模板的引入

 语法格式

template<typename/class 类型参数表>
返回类型 函数模板名(函数参数列表)
{
    函数模板定义体
}

template 是语义是模板的意思,尖括号中先写关键字 typename 或是 class ,后面跟一个类型 T,此类即是虚拟的类型。至于为什么用 T,用的人多了,也就是 T 了。

9.1.3. 函数模板的实例

调用过程是这样的,先将函数模板实再化为函数,然后再发生函数调用。

#include <iostream>
using namespace std;
template <typename T>
void Swap(T& a,T &b )
{
    T t = a;
    a = b;
    b = t;
}
int main()
{
    int ia = 10; int ib = 20;
    Swap(ia,ib);         //Swap<int>(ia,ib);
    cout<<ia<<ib<<endl;
    double da = 10, db = 20;
    Swap(da,db);         //Swap<double>(da,db);
    cout<<da<<db<<endl;
    string sa ="china"; string sb = "America";
    Swap(sa,sb);
    cout<<sa<<sb<<endl;
    return 0;
}

9.1.4. 小结
函数模板,只适用于函数的参数个数相同而类型不同,且函数体相同的情况。如果个数不同,则不能用函数模板。
9.2. 类模板
9.2.1. 引例
Stack 类

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
using namespace std;
class Stack
{
public:
    Stack(int size=1024);
    ~Stack();
    bool isEmpty();
    bool isFull();
    void push(int data);
    int pop();
private:
    int* space;
    int top;
};
Stack::Stack(int size)
{
    space = new int[size];
    top = 0;
}
Stack::~Stack()
{
    delete []space;
}
bool Stack::isEmpty()
{
    return top == 0;
}
bool Stack::isFull()
{
    return top == 1024;
}
void Stack::push(int data)
{
    space[top++] = data;
}
int Stack::pop()
{
    return space[--top];
}
int main()
{
    Stack s(100);
    if(!s.isFull())
        s.push(10);
    if(!s.isFull())
        s.push(20);
    if(!s.isFull())
        s.push(30);
    if(!s.isFull())
        s.push(40);
    if(!s.isFull())
        s.push(50);
    while(!s.isEmpty())
        cout<<s.pop()<<endl;
    return 0;
}

上述栈,如果想模板化,可以 push 和 pop 不同的数据类型。主要由几个因素需要把控。栈中的空间元素类型,压入元素类型,弹出元素类型,三者保持一致即可。

9.2.2. 类模板语法

9.2.2.1. 类模板定义

template<typename T>
class Stack
{
}

9.2.2.2. 类内定义成员函数

template<typename T>
class Stack
{
public:
    Stack(int size)
    {
        space = new T[size];
        top = 0;
    }
}

9.2.2.3. 类外定义函数

template<typename T>
void Stack<T>::push(T data)
{
    space[top++] = data;
}

9.2.2.4. 类模板实例化为模板类

类模板是类的抽象,类是类模板的实例。

Stack<double> s(100);

9.2.3. 类模板实例

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
145
#include <string.h>
using namespace std;
template<typename T>
class Stack
{
public:
    Stack(int size)
    {
        space = new T[size];
        top = 0;
    }
    ~Stack();
    bool isEmpty();
    bool isFull();
    void push(T data);
    T pop();
private:
    T* space;
    int top;
};
template<typename T>
Stack<T>::~Stack()
{
    delete []space;
}
template<typename T>
bool Stack<T>::isEmpty()
{
    return top == 0;
}
template<typename T>
bool Stack<T>::isFull()
{
    return top == 1024;
}
template<typename T>
void Stack<T>::push(T data)
{
    space[top++] = data;
}
template<typename T>
T Stack<T>::pop()
{
    return space[--top];
}
int main()
{
    Stack<double> s(100);      //Stack<string> s(100);
    if(!s.isFull())
        s.push(10.3);
    if(!s.isFull())
        s.push(20);
    if(!s.isFull())
        s.push(30);
    if(!s.isFull())
        s.push(40);
    if(!s.isFull())
        s.push(50);
    while(!s.isEmpty())
        cout<<s.pop()<<endl;
    return 0;
}

9.2.4. 练习

模拟 STL 中 vector 的用法,自己实现之。

#ifndef MYVECTOR_HPP
#define MYVECTOR_HPP
#include <iostream>
using namespace std;
template <typename T> class MyVector;
template <typename T> ostream & operator<<(ostream &out, const MyVector<T> &obj);
template <typename T>
class MyVector
{
public:
    MyVector(int size = 0);
    MyVector(const MyVector<T> &obj);
    MyVector<T> & operator=( MyVector<T> &obj);
    ~MyVector();
    T& operator[] (int index);
    int getSize();
    friend ostream & operator<< <T>(ostream &out, const MyVector<T> &obj);
protected:
    T *m_space;
    int m_len;
};
template <typename T>
int MyVector<T>::getSize()
{
    return m_len;
}
template <typename T>
ostream & operator<< (ostream &out, const MyVector<T> &obj)
{
    for (int i=0; i< obj.m_len; i++)
    {
        out << obj.m_space[i] << " ";
    }
out << endl;
return out;
}
template <typename T>
MyVector<T>::MyVector(int size)
{
    m_space = new T[size];
    m_len = size;
}
template <typename T>
MyVector<T>::MyVector(const MyVector & obj)
{
    m_len = obj.m_len;
    m_space = new T[m_len];
    for (int i=0; i<m_len; i++)
    {
        m_space[i] = obj.m_space[i];
    }
}
template <typename T>
MyVector<T>::~MyVector() //析构函数
{
    if (m_space != NULL)
    {
        delete [] m_space;
        m_space = NULL;
        m_len = 0;
    }
}
template <typename T>
T& MyVector<T>::operator[] (int index)
{
    return m_space[index];
}
template <typename T>
MyVector<T> & MyVector<T>::operator=( MyVector<T> &obj)
{
    delete[] m_space;
    m_space = NULL;
    m_len = 0;
    m_len = obj.m_len;
    m_space = new T[m_len];
    for (int i=0; i<m_len; i++)
    {
        m_space[i] = obj[i];
    }
    return *this;
}
#endif // MYVECTOR_HPP

测试代码:

#include <iostream>
#include "myvector.hpp"
using namespace std;
int main()
{
    MyVector<int> a(10);
    for(int i=0; i<10; i++)
    {
        a[i] = i+100;
    }
    MyVector<int> b(a);
    cout<<b[2]<<b[1]<<endl;
    MyVector<int> c;
    c = a;
    cout<<b[2]<<b[1]<<endl;
    cout<<a;
    return 0;
}

注:

《C++编程思想》第 15 章(第 300 页):

模板定义很特殊。由 template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
技术教程

第十五章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-2-4 9:30:00

技术教程

第十七章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-2-6 9:30:00

0 条回复 A文章作者 M管理员
夸夸
夸夸
还有吗!没看够!
    暂无讨论,说说你的看法吧
个人中心
购物清单
优惠代劵
今日签到
有新私信 私信列表
快速搜索
关注我们
  • 扫码打开当前页

你已经到达了世界的尽头

  • 3350

    文章数目

  • 223

    注册用户

  • 1766

    总评论数

  • 287

    建站天数

  • 47552

    总访问量

  • 波浪
  • 波浪
  • 波浪
  • 波浪