程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++ template隨筆,template隨筆

C++ template隨筆,template隨筆

編輯:C++入門知識

C++ template隨筆,template隨筆


話題從重用開始說起:

最基本的重用,重用一個方法,被重用的邏輯被抽取封裝成為方法,之後我們把方法當成一種工具來使用(處理數據,輸入輸出,或者改變狀態)。

來到了面向對象的時代,如果這個方法出現父類上面就是繼承,如果這個方法出現在其他對象上就是代理,如果子類想要重用父類的接口又不想重用實現那麼就是多態。

但是這些重用都是基於相同的數據類型,方法創建出來後接收參數都是固定的類型,對於多態,可以通過子類來實現不同行為,但是方法總歸還是接收一個固定父類型(或者接口)參數。

想想有沒有這樣的需求,兩個完全不同的類型,他們之間不存在繼承關系,但是卻需要同樣的處理邏輯,比如說各種類型都需要排序,比如說各種類型都有集合處理的需求。

那麼能不能讓方法接收不同類型來實現重用呢?C++的Template就是解決這樣問題。

 

模板方法

既然這樣需求不同類型卻需要相同處理方法,所以有了模板方法,

template<typename T>
T Add(T a, T b)
{
    return a + b;
};

int main()
{
    string s1 = "Hello";
    string s2 = "World";
    cout << Add(12,13) << endl;
    cout << Add(s1,s2) << endl;
    return 0;
}; 輸出: 25 HelloWorld

 模板類

方法都能模板化,那麼類怎麼能夠不模板化, 作為面向對象的C++,所以有了模板類

把這些模板方法組合起來,再加上模板成員就形成了一個模板類,這些概念和行為和一般的類是一樣的。

 

template<typename T>
class Calculator
{
public:
    T m_variable;
    virtual T Add(T a, T b)
    {
        return a + b;
    };

    T Minus(T a, T b)
    {
        return a - b;
    };
};

int main()
{
    Calculator<int> c;
    cout << c.Add(2,3) << endl;
    cout << c.Minus(9,5) << endl;

    string s1 = "Hello";
    string s2 = "World";
    Calculator<string> d;
    cout << d.Add(s1,s2) << endl;
    //cout << d.Minus(s1,s2) << endl;
    return 0
} 

 

想想為什麼最後那句注釋可以編譯過,但是打開那句就編譯不過了。

我的理解,當模板類實例化的過程,如果沒有用到的方法不會被加入被實例化的模板類中,除非你顯示調用了模板類的方法。

模板類繼承

既然是類,當然不能少了繼承,模板類的繼承可以分為

直接從模板類繼承

template<typename T>
class SuperCalculator : public Calculator<T>
{
public:
    T m_variable;
    virtual T Add(T a, T b)//多態
    {
        return a + b + b;
    };

    T Multi(T a, T b)//子類
    {
        return a * b;
    };
};

 
int main()
{
    SuperCalculator<int> sc;
    cout << sc.Add(2,3) << endl;
    cout << sc.Minus(9,5) << endl;
    cout << sc.Multi(9,5) << endl;
    return 0;
};

輸出 8,4,45

從具體類繼承

class SuperIntCalculator: public Calculator<int>
{
public:
    virtual int Add(int a, int b)
    {
        return a + b + a;
    };

    int Multi(int a, int b)
    {
        return a * b;
    };
};

int main()
{
    SuperIntCalculator sc;
    cout << sc.Add(2,3) << endl;
    cout << sc.Minus(9,5) << endl;
    cout << sc.Multi(9,5) << endl;


    return 0;
};

輸出 7, 4, 45

 

模板特例化(偏特化) 

模板類可以通過繼承可以在垂直方向變化,但是類型本身也是一個水平的維度,C++為這個維度提供了變化,對於某種具體類的模板類可以擁有特殊的行為,因此我們成為特例化。

template<typename T>
class TClass
{
public:
    void PrintInfo()
    {
        printf("Hello common\n");
    };
};

template<>
class TClass<int>//特例化
{
public:
    void PrintInfo()
    {
        printf("Hello int\n");
    };
};

template<typename T>
TClass<T> * GetTClassObject(T a)
{
    return new TClass<T>;
};


int main()
{
    GetTClassObject("Hello")->PrintInfo();
    GetTClassObject(4.5)->PrintInfo();
    GetTClassObject(5)->PrintInfo();

    return 0;
};

輸出
Hello Common
Hello Common
Hello Int

如果一個模板類需要接受兩個或者兩個以上的類型來實現具體類,當其中一個類型是某個具體類的時候有特殊的行為,那麼就成為偏特化。

繼承是垂直方向上的特例化,但是特例化不是傳統面向對象體系中的概念,可以類比但不要混淆,特例化是是另外一個維度(水平),因此特例化不僅僅可以作用在類上,也能作用在模板方法上。

 

比較

>>模板和模板模式(Template Method Design Pattern)

這個設計模式也是來解決不同類型的卻有相同的處理邏輯,這個思想是一致的。但是實現卻不同,模板模式由子類去實現模板方法的每一個步驟(或者某個步驟),而且這個模式的假設是所有的類型都是來自於相同的基類,沒有解決我們最開始非固定類型。C++模板實現邏輯在類型外面(怎麼感覺又有點像策略模式,但是策略模式需要相同的接口或者基類),而類型本身可以針對不同基類的類型。其實對於模板類(方法)而言,他們雖然沒有共同的基類,但是再仔細想想,要在一個模板類中類型需要有一個抽象共性,但是這個共性不是以基類形式來表達,比如說排序,那麼輸入類型必須都要能比較大小,比如說集合,那麼輸入類型都要有“一個一個”的概念(好像不好理解,vector能處理流體問題嗎?)

>>模板和宏

這兩個東西很容易放在一起說,比如一個簡單模板類可以通過宏來實現沒有問題。

但是兩者是從不同角度來解決重用問題的,模板是為不同類型提供相同邏輯的重用,是站在類型的角度上看問題。宏是為代碼級別的重用,站在少寫代碼的角度來看問題。

所以他們有重疊的部分。也提供對方不能提供的功能

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