C++学习笔记(8)-模板

模板

模板主要是提供一种处理方式,相当于加强版的函数处理,里面的参数类型,处理方式都能够被模板化,传统的函数处理是不能够针对多种处理方式的,所以会出现函数的重载问题。
模板主要包括两个方面:
- 针对函数的模板,格式:template 函数返回值 函数名称 (函数参数){函数处理};例如template void swap(T& a, T& b){},其中的class能够变成typename
- 针对类的模板,格式template class classname{ … };例子:template class A{public: T a; T b; T hy(T c, T &d);};当函数在外部声明的是姑姑也template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},所以为template T A::hy(T c, T &d);

针对函数的模板

格式:

template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)

   {

      函数体

   }

例子:

template <class T> T add (T a,T b){
return a+b;}

当调用这样的模板函数时类型T就会被被调用时的类型所代替,比如swap(a,b)其中a和b是int 型,这时模板函数swap中的形参T就会被int 所代替,模板函数就变为swap(int &a, int &b)。而当swap(c,d)其中c和d是double类型时,模板函数会被替换为swap(double &a, double &b),这样就实现了函数的实现与类型无关的代码。

针对类的模板

类模板的格式

template <class T1,class T2...> class A
{
...
T1 add(T1 t1,T2 t2);
}
template <class T1,class T2> T1 A<T1,T2>::add(T1 t1,T2 t2)   
{
  return (T1)(t1+t2);
}

调用:(假如有两个参数)
那么
A<int,double> m
m就是变量,其中里面的T1对应int类性数据,T2对应double类型数据

类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为A m;在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。

外部函数声明方式:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体}
比如有两个模板形参T1,T2的类A中含有一个void h()函数,则定义该函数的语法为:

    template<class T1,class T2> void A<T1,T2>::h(){}
    
注意模板的声明只能够在全局变量中申明,不能够在局部声明
例子:

#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

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 是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值