C++模板实战2:模板类

1        借助函数模板可以使算法脱于具体数据类型之外,借助模板类可以使数据结构脱于具体数据类型之外,从而专注于数据存取方法及数据间的关联方式,抽象的数据结构可以和具体数据类型无关。类模板和函数模板一样以template<typename...>开头,但是类模板实例化和函数模板实例化有一点不太一样,函数模板可以从函数参数自动推导模板参数从而可以省略模板参数的书写,而类模板即使有默认模板参数其<>还是不能省略,即最简单的类模板实例化也是类似于:class test<> one;其中采用默认模板参数可以省略参数单数<>不能省略。而且默认的模板参数尽量在安排在众模板参数的后面,因为模板实例化是按照参数位置来推导的。下面是一个简易的线程安全的栈操作(部分):

#include<iostream>
#include<memory>
#include<mutex>
#include<utility>
using namespace std;
template<typename T>
class myStack{//只提供了push和try_pop操作
    public:
        myStack():head(nullptr){}
        myStack(myStack& one)=delete;//防止多个栈共享head
        myStack& operator=(const myStack& one)=delete;
        ~myStack(){
            while(head){
                node* temp=head->next;
                delete head;
                head=temp;
            }
        }
        void push(T& value){
            node* new_node=new node(value);
            unique_lock<mutex> lock(m);
            new_node->next=head;
            head=new_node;
        }
        bool try_pop(T& value){//栈内有元素则返回true,否则返回false,元素值通过函数参数引用返回
            unique_lock<mutex> lock(m);
            if(head){
                value=move(*head->data);
                head=head->next;
                return true;
            }
            else{
                return false;
            }
        }
        bool empty() const{
            unique_lock<mutex> lock(m);
            return head==nullptr?true:false;
        }
    private:
        struct node{
            shared_ptr<T> data;
            node* next;
            node(T& value):data(std::make_shared<T>(value)){}
            node():next(nullptr){}
        };
        node* head;
        mutex m;//互斥量保护栈存取
};
int main(){
    myStack<string> stackOne;
    string s("hello world");
    stackOne.push(s);
    string temp;
    if(stackOne.try_pop(temp))
        cout<<temp<<endl;
    return 0;
}
       

2      模板与继承:若基类是模板类,子类必须指定基类的模板参数,可以如下:

template<typename T>
class base;//模板基类

template<typename T>
class derived1: public base<T>;//子类和基类使用共同的模板参数

template<typename T1,typename T2>
class derived2:public base<T2>;//子类和基类模板参数不同

class derived3:public base<int>;//子类不是模板类,基类需实例化

3     模板类与成员函数:模板类的成员函数可以使用和类模板相同的模板参数,也可以使用不同于类模板的参数。成员函数类外实现时要注意带上类模板的参数。实例如下:

template<typename T> 
class test{
  public:
      void fun(){cout<<"fun"<<endl;};//和类使用相同的模板参数且在类中实现
     
      void fun1();

      template<typename T1>
      void fun2();
};
template<typename T>//和类模板参数一样且类外实现
void test<T>::fun1(){cout<<"fun1"<<endl;}

temlate<typename T>//类外实现注意带上类的模板参数
template<typename T1>
void test<T>::fun2(){cout<<"fun2"<<endl;}

4       类模板的静态成员:普通类中的静态成员在类的多次实例化对象中静态成员始终只有一份,在模板类中静态成员是否如此呢?首先模板类实例化后具有相同模板参数的实例化才是同样的类,那么相同的模板实例化代码共享同一份静态数据成员。如下:

template<typename T>
class test{   
   public:
       staitc int data;
};
template<typename T> int test<T>::data=0;//静态成员的类外初始化

test<int> one;
test<int> two;//one和two实例化后共享data的内存地址
test<double> three;

5      友元模板类:友元耦合性太强,一般不怎么用,要用友元类模板可以如下:

template<typename T>
class test;

class one{
   public:
       template<typename T>
       friend class test;
};

6       嵌套模板实现tuple:std::pair表示一个二元组,tuple可以表示多元元组,C++11通过变长模板实现std::tuple,变长模板对模板参数包的解包对变长模板参数解析。这里通过嵌套实现tuple,代码如下:

#include<iostream>
#include<string>
using namespace std;
template<typename T,typename N>
struct Tuple{
  T value;
  N next;
  Tuple(T const& v,N const& n):value(v),next(n){}
};

template<typename T,typename N>
Tuple<T,N> push(T const& v,N const& n){
  return Tuple<T,N>(v,n);
}

int main(){
  using Tuple2=Tuple<int,char>;
  using Tuple3=Tuple<float,Tuple2>;
  using Tuple4=Tuple<string,Tuple3>;
  Tuple4 myTuple=push(string("PI"),push(3.14f,push(1,'p')));
  cout<<myTuple.value<<" "<<myTuple.next.value<<" "<<myTuple.next.next.value<<" "<<myTuple.next.next.next<<endl;
  return 0;
}
程序输出:

PI 3.14 1 p










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值