C++ 模板

C++ 模板


一、前言

模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。

模板是创建泛型类或函数的蓝图或公式。其是一种将数据类型作为参数的通用程序设计方法。允许开发人员编写可以处理各种数据类型的代码,而无需为每种数据类型编写不同的代码。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。

每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。

二、模板的定义

1. 函数模板

模板函数定义的一般形式

template <typename type> ret-type func-name(parameter list)
{
   // 函数的主体
}

在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。相当于int、float等等。

模板是一种通用程序设计方法,它允许开发人员编写可以处理各种数据类型的代码。模板定义了一种通用的程序结构,该结构可以使用任何数据类型。例如,我们可以编写一个模板函数来交换任何两个变量,无论它们是整数、浮点数还是其他类型的数据。

一个简单的示例,交换输入的两个变量数据:

#include <iostream>
using namespace std;
template <typename T1>
void Swap(T1& a, T1& b)
{
    T1 t = a;
    a = b;
    b = t;
}
int main()
{
    int a = 2;
    int b = 3;
    cout <<"a = " << a << ";  b = " << b <<endl;
    Swap(a,b);
    cout << "Swap: \n" <<"a = " << a << ";  b = " << b <<endl;
    float c = 0.02;
    float d = 0.03;
    cout <<"c = " << c << ";  d = " << d <<endl;
    Swap(c,d);
    cout << "Swap: \n" <<"c = " << c << ";  d = " << d <<endl;
    char x = 'x';
    char y = 'y';
    cout <<"x = " << x << ";  y = " << y <<endl;
    Swap(x,y);
    cout << "Swap: \n" <<"x = " << x << ";  y = " << y <<endl;
    return 0;
}

运行结果

a = 2;  b = 3
Swap:
a = 3;  b = 2
c = 0.02;  d = 0.03
Swap:
c = 0.03;  d = 0.02
x = x;  y = y
Swap:
x = y;  y = x

下面也是函数模板的示例,返回两个数中的最大值:

#include <iostream>
#include <string>
 
using namespace std;
 
template <typename T>
inline T const& Max (T const& a, T const& b) 
{ 
    return a < b ? b:a; 
} 
int main ()
{
 
    int i = 39;
    int j = 20;
    cout << "Max(i, j): " << Max(i, j) << endl; 
 
    double f1 = 13.5; 
    double f2 = 20.7; 
    cout << "Max(f1, f2): " << Max(f1, f2) << endl; 
 
    string s1 = "Hello"; 
    string s2 = "World"; 
    cout << "Max(s1, s2): " << Max(s1, s2) << endl; 
 
    return 0;
}

运行结果

Max(i, j): 39
Max(f1, f2): 20.7
Max(s1, s2): World

2. 类模板

正如我们定义函数模板一样,我们也可以定义类模板。泛型类声明的一般形式如下所示:

template <class type> class class-name 
{
.
.
.
}

来看一个简单的类模板示例:

#include <iostream>
using namespace std;
template <typename T>
class Pow{
public:
    T process(T v)
    {
        return v * v;
    }
};
int main()
{
    Pow<int> PowInt;
    Pow<double> PowDouble;
    cout << "5 * 5 = " << PowInt.process(5) <<endl;
    cout << "0.5 * 0.5 = " << PowDouble.process(0.5) <<endl;
}

运行结果:

5 * 5 = 25
0.5 * 0.5 = 0.25

在这个例子中,typename T表示类型参数。在创建一个Pow对象时,我们可以指定我们想要存储的数据类型。例如,我们可以创建一个Pow对象来操作整数,或者创建一个Pow对象来操作浮点数。

下面的示例定义了类 Stack<>,并实现了泛型方法来对元素进行入栈出栈操作:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <string>
#include <stdexcept>
 
using namespace std;
 
template <class T>
class Stack { 
  private: 
    vector<T> elems;     // 元素 
 
  public: 
    void push(T const&);  // 入栈
    void pop();               // 出栈
    T top() const;            // 返回栈顶元素
    bool empty() const{       // 如果为空则返回真。
        return elems.empty(); 
    } 
}; 
 
template <class T>
void Stack<T>::push (T const& elem) 
{ 
    // 追加传入元素的副本
    elems.push_back(elem);    
} 
 
template <class T>
void Stack<T>::pop () 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::pop(): empty stack"); 
    }
    // 删除最后一个元素
    elems.pop_back();         
} 
 
template <class T>
T Stack<T>::top () const 
{ 
    if (elems.empty()) { 
        throw out_of_range("Stack<>::top(): empty stack"); 
    }
    // 返回最后一个元素的副本 
    return elems.back();      
} 
 
int main() 
{ 
    try { 
        Stack<int>         intStack;  // int 类型的栈 
        Stack<string> stringStack;    // string 类型的栈 
 
        // 操作 int 类型的栈 
        intStack.push(7); 
        cout << intStack.top() <<endl; 
 
        // 操作 string 类型的栈 
        stringStack.push("hello"); 
        cout << stringStack.top() << std::endl; 
        stringStack.pop(); 
        stringStack.pop(); 
    } 
    catch (exception const& ex) { 
        cerr << "Exception: " << ex.what() <<endl; 
        return -1;
    } 
}

运行结果:

7
hello
Exception: Stack<>::pop(): empty stack

三、tips

1. C++ 中 typename 和 class 的区别

在 C++ Template 中很多地方都用到了 typename 与 class 这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?

相信学习 C++ 的人对 class 这个关键字都非常明白,class 用于定义类,在模板引入 c++ 后,最初定义模板的方法为template<class T>......这里 class 关键字表明T是一个类型,后来为了避免 class 在这两个地方的使用可能给人带来混淆,所以引入了 typename 这个关键字,它的作用同 class 一样表明后面的符号为一个类型,这样在定义模板的时候就可以使用template<typename T> ......

typename 难道仅仅在模板定义中起作用吗?其实不是这样,typename 另外一个作用为:使用嵌套依赖类型(nested depended name),如下所示:

class MyArray 
{ 
    publictypedef int LengthType;
.....
}

template<class T>
void MyMethod( T myarr ) 
{ 
    typedef typename T::LengthType LengthType; 
    LengthType length = myarr.GetLength; 
}

这个时候 typename 的作用就是告诉 c++ 编译器,typename 后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有 typename,编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。

2. 函数模板可以重载,只要它们的形参表不同即可

下面的两个模板可以同时存在

template<class T1, class T2>
void print(T1 arg1, T2 arg2)
{
  cout<<arg1<<" "<<arg2<<endl; 
}
template<class T>
void print(T arg1, T arg2)
{
  cout<< arg1<< " "<< arg2<< endl;
}

参考链接

C++模板和泛型编程详解 - 知乎 (zhihu.com)

菜鸟教程-C++模板

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值