程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ Primer 學習筆記_45_模板(三):缺省模板參數(借助標准模板容器deque實現Stack模板)、成員模板、關鍵字typename

C++ Primer 學習筆記_45_模板(三):缺省模板參數(借助標准模板容器deque實現Stack模板)、成員模板、關鍵字typename

編輯:C++入門知識

C++ Primer 學習筆記_45_模板(三):缺省模板參數(借助標准模板容器deque實現Stack模板)、成員模板、關鍵字typename


一、缺省模板參數

1、stack內存能否借助標准模板容器管理呢?答案是肯定的,只需要多傳一個模板參數即可,而且模板參數還可以是缺省的,如下:

 

template  > //此處末尾必須有空格,否則編譯出錯
class Stack
{
…
private:
    CONT c_;
};

 

如果沒有傳第二個參數,默認為deque 雙端隊列,當然我們也可以傳遞std::vector

 

2、示例:借助標准模板容器deque管理實現stack模板類

這裡的Stack是適配器,STL六大組件之一,代碼復用,不是通過繼承;通過現有的類實現模板類

Stack.h:

 

#ifndef _STACK_H_
#define _STACK_H_

#include 
#include 
using namespace std;

template  > //此處末尾必須有空格,否則編譯出錯
class Stack
{
public:
    Stack() : c_()
    {
    }
    ~Stack()
    {
    }

    void Push(const T &elem)
    {
        c_.push_back(elem);
    }
    void Pop()
    {
        c_.pop_back();
    }
    T &Top()
    {
        return c_.back();
    }
    const T &Top() const
    {
        return c_.back();
    }
    bool Empty() const
    {
        return c_.empty();
    }
private:
    CONT c_;  //借助標准模板容器 deque 管理實現stack
};

#endif // _STACK_H_

 

main.cpp:

 

#include "Stack.h"
#include 
#include 
using namespace std;


int main(void)
{
    //Stack s;  //默認是deque實現
    Stack > s;
    s.Push(1);
    s.Push(2);
    s.Push(3);

    while (!s.Empty())
    {
        cout << s.Top() << endl;
        s.Pop();
    }
    return 0;
}

 

輸出為 3 2 1

即如果沒有傳遞第二個參數,堆棧和壓棧等操作直接調用deque 的成員函數,也由deque 管理內存。

如程序中傳遞vector ,則由vector 成員函數處理。

 

 

二、成員模板

來看下面的例子:

 

#include 
using namespace std;


template 
class MyClass
{
private:
    T value;
public:
    void Assign(const MyClass &x)
    {
        value = x.value;
    }
};

int main(void)
{
    MyClass d;
    MyClass i;

    d.Assign(d);        // OK
    d.Assign(i);        // Error
    return 0;
}

 

因為i 和 d 的類型不同,故會編譯出錯。可以用成員模板的方法解決:
#include 
using namespace std;

template 
class MyClass
{
private:
    T value;
public:
    MyClass() {}
    template 
    MyClass(const MyClass &x) : value(x.GetValue())
    {

    }
    template 
    void Assign(const MyClass &x)
    {
        value = x.GetValue(); //當不同類型時,value私用,應通過成員函數調用
    }
    T GetValue() const
    {
        return value;
    }
};

int main(void)
{
    MyClass d;
    MyClass i;
    d.Assign(d);        // OK
    d.Assign(i);        // OK

    MyClass d2(i);

    return 0;
}
為了支持 MyClassd2(i); 故也要將拷貝構造函數實現為成員模板函數,同理,如果想支持 d = i ; 也要將賦值運算符實現為成員模板。實際上auto_ptr 中的實現就使用了成員模板,因為要支持類似下面的運算: auto_ptr x; auto_ptr y; x = y;       三、typename 關鍵字   看下面的例子: typenameT::SubType*ptr_;如果前面沒有typename 修飾,則SubType會被認為是T類型內部的靜態數據成員,推導下去,* 就不認為是指針,而被認為是乘號,編譯的時候就出錯了。加上修飾,就知道SubType 是T 內部的自定義類型,ptr是指向這種類型的指針,編譯通過。
#include 
using namespace std;

template 
class MyClass
{
private:
    typename T::SubType* ptr_;
};

class Test
{
public:
    typedef int SubType;  //如果Test中沒有定義SubType類型,則編譯會失敗
};

int main(void)
{
    MyClass mc;
    return 0;
}
    四、派生類與模板、面向對象與泛型編程

(一)、派生類與模板

1、為了運行的效率,類模板是相互獨立的,即獨立設計,沒有使用繼承的思想。對類模板的擴展是采用適配器(adapter)來完成的(如之前使用deque實現Stack)。通用性是模板庫的設計出發點之一,這是由泛型算法(algorithm)和函數對象(functor)等手段達到的。


2、派生的目標之一也是代碼的復用和程序的通用性,最典型的就是MFC,派生類的優點是可以由簡到繁,逐步深入,程序編制過程中可以充分利用前面的工作,一步步完成一個復雜的任務。


3、模板追求的是運行效率,而派生追求的是編程的效率。

 

(二)、面向對象與泛型編程

1、面向對象與泛型都依賴於某個形式的多態

(1)面向對象

動態多態(虛函數)

(2)泛型

靜態多態(模板類,模板函數)

2、面向對象中的多態在運行時應用存在繼承關系。我們編寫使用這些類的代碼,忽略基類與派生類之間的類型差異。只要使用基類指針或者引用,基類類型對象、派生類類型對象就可以共享相同的代碼。


3、在泛型編程中,我們所編寫的類和函數能夠多態地用於編譯時不相關的類型。一個類或一個函數可以用來操縱多種類型的對象。

參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規范

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved