函數(shù)模板與類模板

函數(shù)模板

函數(shù)模板的概念

為了提高效率董朝,實現(xiàn)代碼復用鸠项,C++提供了一種處理機制,即使用函數(shù)模板子姜。
定義函數(shù)模板的格式

template <模板參數(shù)表>
返回類型名 函數(shù)模板名(參數(shù)表)
{
  函數(shù)體的定義
}

函數(shù)模板的定義以關鍵字template開頭祟绊,該關鍵字之后是使用尖括號<>括起來的”模板參數(shù)表“。

函數(shù)模板中函數(shù)體的定義方式與定義普通函數(shù)時類似哥捕。

函數(shù)模板的示例

程序9-1 定義求絕對值的函數(shù)模板并進行不同的調用

#include <iostream>
using namespace std;
template <typename T>

T abs(T x)
{
    return x<0?-x:x;
}

int main()
{
    int n = -5;
    int m = 10;
    double d = -5;
    float f = 3.2;
    cout<<n<<"的絕對值是: "<<abs(n)<<endl;
    cout<<m<<"的絕對值是: "<<abs(m)<<endl;
    cout<<d<<"的絕對值是: "<<abs(d)<<endl;
    cout<<f<<"的絕對值是: "<<abs(f)<<endl;
    return 0;
} 

-5的絕對值是: 5
10的絕對值是: 10
-5的絕對值是: 5
3.2的絕對值是: 3.2

函數(shù)指針只能指向模板的實例牧抽,而不能指向模板本身。

程序9-2 定義對象交換的函數(shù)模板

#include <iostream>
using namespace std;

template <class T>
void Swap(T &x,T &y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

class myDate
{
    public:
        myDate();
        myDate(int,int,int);
        void printDate() const;
    private:
        int year,month,day;
};

myDate::myDate()
{
    year = 1970;
    month = 1;
    day = 1;
}

myDate::myDate(int y,int m,int d)
{
    year = y;
    month = m;
    day = d;
}

void myDate::printDate()const
{
    cout<<year<<"/"<<month<<"/"<<day;
    return;
}

int main()
{
    int n = 1,m = 2;
    Swap(n,m);
    double f = 1.2,g = 2.3;
    Swap(f,g);
    myDate d1,d2(2000,1,1);
    Swap(d1,d2);
    return 0;
}

顯式實例化函數(shù)模板的格式

模板名 <實際類型參數(shù)1遥赚,實際類型參數(shù)2扬舒,...>

例如,程序9-2主函數(shù)中可以寫成

Swap<int>(n,m);
Swap<myDate>(d1,d2);

函數(shù)模板可以帶多個類型參數(shù)凫佛。

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

例9-1 定義對象比較的函數(shù)模板

template <typename T>
int myCompare(const T& left,const T& right)
{
  if(left<right)
  {
      return -1;
  }
  else if(right < left)
  {
    return 1;
  }
  else return 0;
}

程序9-3 對象排序程序

#include <iostream>
using namespace std;

template <typename T>
int myCompare(const T& left,const T& right)
{
  if(left<right)
  {
      return -1;
  }
  else if(right < left)
  {
    return 1;
  }
  else return 0;
}

template <class T>
void Swap(T &x,T &y)
{
    T tmp = x;
    x = y;
    y = tmp;
}

int main()
{
    string arraystring[10] = {"shang","xia","zuo","you","qian","hou","dong","xi","nan","bei"};
    int j;
    string temp;
    for(int i=1;i<10;i++)
    {
        j = i;
        while(j>0&&myCompare<string>(arraystring[j-1],arraystring[j])>0)
        {
            Swap(arraystring[j],arraystring[j-1]);
            j--;
        }
    }
    for(int i = 0;i<10;i++)
        cout<<arraystring[i]<<",";
}

bei,dong,hou,nan,qian,shang,xi,xia,you,zuo,

函數(shù)或函數(shù)模板調用語句的匹配順序

函數(shù)模板可以重載讲坎,只要他們的形參表不同即可。

程序9-4 重載函數(shù)模板

#include <iostream>
using namespace std;

class myDate
{
    public:
        myDate();
        myDate(int,int,int);
        friend ostream & operator<<(ostream & os,const myDate & c); //友元愧薛,插入 
    private:
        int year,month,day;
};

myDate::myDate()
{
    year = 1970;
    month = 1;
    day = 1;
}

myDate::myDate(int y,int m,int d)
{
    year = y;
    month = m;
    day = d;
}

ostream & operator<<(ostream & os,const myDate & c)
{
    os<<c.year<<"/"<<c.month<<"/"<<c.day;
    return os;
}

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;
}

int main()
{
    int n = 1,m = 2;
    print(n,m); //輸出1晨炕, 2
    myDate d1,d2(2000,1,1);
    print(d1,d2);
    print(n,d1);
    return 0; 
}

1, 2
1970/1/1, 2000/1/1
1, 1970/1/1

程序9-5 函數(shù)調用匹配順序

#include <iostream>
using namespace std;
template <class T>
T Max(T a,T b)
{
    cout<<"Template Max 1"<<endl;
    return 0;
}

template <class T,class T2>
T Max(T a,T2 b)
{
    cout<<"Template Max 2"<<endl;
    return 0;
}

double Max(double a,double b)
{
    cout<<"Function Max"<<endl;
    return 0;
}

int main()
{
    int i=4,j=5;
    Max(1.2,3.4);
    Max(i,j);
    Max(1.2,3);
    return 0;
}

Function Max
Template Max 1
Template Max 2

類模板

當需要編寫多個形式和功能都相似的類時,可以使用類模板機制毫炉。

類是對一組對象的公共性質的抽象瓮栗,而類模板則是對不同類的公共性質的抽象,因此類模板是屬于更高層次的抽象瞄勾。

通過類模板遵馆,可以實例化一個個的類。

聲明類模板的格式

template <模板參數(shù)表>
class 類模板名
{
   類體定義 
}

如果需要在類模板以外定義其成員函數(shù)丰榴,則需要采用以下格式

template <模板參數(shù)表>
返回類型名 類模板名<模板參數(shù)標識符列表>::成員函數(shù)名(參數(shù)表)
{
  函數(shù)體
}

當使用類模板創(chuàng)建對象時货邓,要隨類模板名給出對應于類型形參或普通形參的具體實參,格式

類模板名 <模板參數(shù)表> 對象名1,...,對象名n;

或

類模板名 <模板參數(shù)表> 對象名1(構造函數(shù)實參),...,對象名n(構造函數(shù)實參);

編譯器由類模板生成類的過程稱為類模板的實例化四濒。由類模板實例化得到的類稱為模板類换况。

類模板示例

程序9-6 類模板

#include <iostream>
#include <string>
using namespace std;

template <class T1,class T2>
class Pair
{
    public:
        T1 first;
        T2 second;
        Pair(T1 k,T2 v):first(k),second(v){}
        bool operator<(const Pair<T1,T2>& p)const;
};

template <class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const    //Pair的成員函數(shù)operator<
{
    return first<p.first;   
} 

int main()
{
    Pair<string,int> student1("Tom",19);
    Pair<string,int>student2("Jim",21);
    Pair<int,int>coordinate(10,20);
    Pair<string,string>dic("word","單詞");
    cout<<"學生1:"<<student1.first<<" "<<student1.second<<endl;
    cout<<"學生2:"<<student2.first<<" "<<student2.second<<endl;
    cout<<"坐標: "<<coordinate.first<<" "<<coordinate.second<<endl;
    cout<<"字典項: "<<dic.first<<" "<<dic.second<<endl;
    bool a = student1<student2;
    if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
    else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
    return 0;
}

學生1:Tom 19
學生2:Jim 21
坐標: 10 20
字典項: word 單詞
Tom位于Jim之后

程序9-7 類模板

#include <iostream>
using namespace std;
template <class T>

class TestClass
{
    public:
        T buffer[10];       //T類型的數(shù)據(jù)成員buffer數(shù)組大小固定為10
        T getData(int j);   //獲取T類型buffer(數(shù)組)的第j個分量 
};

template <class T>
T TestClass<T>::getData(int j)
{
    return *(buffer+j);
}

int main()
{
    TestClass<char> ClassInstA;
    int i;
    char cArr[6] = "abcde";
    for(i=0;i<5;i++)
        ClassInstA.buffer[i] = cArr[i];
    for(i = 0;i<5;i++)
    {
        char res = ClassInstA.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
    TestClass<double> ClassInstF;
    double fArr[6] = {12.1,23.2,34.3,45.4,56.5,67.6};
    for(i=0;i<6;i++)
        ClassInstF.buffer[i]=fArr[i]-10;
    for(i=0;i<6;i++)
    {
        double res = ClassInstF.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
    return 0;
}

a  b  c  d  e
2.1  13.2  24.3  35.4  46.5  57.6

程序9-8 在類模板中使用函數(shù)模板

#include <iostream>
#include <string>
using namespace std;
template <class T1,class T2>
class Pair
{
    public:
        T1 first;
        T2 second;
        Pair(T1 k,T2 v):first(k),second(v){}
        bool operator<(const Pair<T1,T2>& p)const;
        template <class T>
        void print(T x)
        {
            cout<<x<<endl;
        }
};

template <class T1,class T2>
bool Pair<T1,T2>::operator<(const Pair<T1,T2> & p) const    //Pair的成員函數(shù)operator<
{
    return first<p.first;   
}

int main()
{
    Pair<string,int> student1("Tom",19);
    Pair<string,int>student2("Jim",21);
    Pair<int,int>coordinate(10,20);
    Pair<string,string>dic("word","單詞");
    cout<<"學生1:"<<student1.first<<" "<<student1.second<<endl;
    cout<<"學生2:"<<student2.first<<" "<<student2.second<<endl;
    cout<<"坐標: "<<coordinate.first<<" "<<coordinate.second<<endl;
    cout<<"字典項: "<<dic.first<<" "<<dic.second<<endl;
    bool a = student1<student2;
    if(a==0)cout<<student1.first<<"位于"<<student2.first<<"之后"<<endl;
    else cout<<student1.first<<"位于"<<student2.first<<"之前"<<endl;
    student1.print<string>(student1.first);
    coordinate.print<int>(coordinate.first);
    return 0;
}

學生1:Tom 19
學生2:Jim 21
坐標: 10 20
字典項: word 單詞
Tom位于Jim之后
Tom
10

程序9-9 類模板中使用靜態(tài)成員

#include <iostream>
using namespace std;
template <typename T>
class Test
{
    public:
        Test(T num)
        {
            k += num;
        }
        Test()
        {
            k += 1;
        }
        static void incrementK()
        {
            k += 1;
        }
        static T k;
};

template <typename T>
T Test<T>::k = 0;

int main()
{
//  static Field;
    Test<int> a;
    Test<double>b(4);
    cout<<"Test<int>::\tk="<<a.k<<endl;
    cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
    Test<int> v;
    Test<double> m;
    cout<<"Test<int>::\tk="<<Test<int>::k<<endl;
    cout<<"Test<double>::\tk="<<Test<double>::k<<endl;
//  static Function
    cout<<endl;
    Test<int>::incrementK();
    cout<<"調用Test<int>::incrementK() Test<int>::k="<<Test<int>::k<<endl;
    Test<double>::incrementK();
    cout<<"調用Test<double>::incrementK() Test<double>::k="<<Test<double>::k<<endl;
    return 0;
}

Test<int>::     k=1
Test<double>::  k=4
Test<int>::     k=2
Test<double>::  k=5

調用Test<int>::incrementK() Test<int>::k=3
調用Test<double>::incrementK() Test<double>::k=6

程序9-10 使用普通參數(shù)的類模板

#include <iostream>
using namespace std;
template <int i>
class TestClass
{
    public:
        int buffer[i];
        int getData(int j);
};

template <int i>
int TestClass<i>::getData(int j)
{
    return *(buffer+j);
};

int main()
{
    TestClass<6> ClassInstF;
    int i;
    double fArr[6]={12.1,23.2,34.3,45.4,56.5,67.6};
    for(i=0;i<6;i++)
        ClassInstF.buffer[i] = fArr[i]-10;
        for(i=0;i<6;i++)
        {
            double res = ClassInstF.getData(i);
            cout<<res<<"  ";
        }
        cout<<endl;
}

2  13  24  35  46  57

類模板與繼承

類模板和類模板之間职辨、類模板和類之間可以互相繼承,他們之間的常見派生關系有:

  • 普通類繼承模板類戈二。
  • 類模板繼承普通類舒裤。
  • 類模板繼承類模板。
  • 類模板繼承模板類觉吭。

程序9-11 普通類繼承模板類

#include <iostream>
using namespace std;
template<class T>
class TBase     //類模板腾供,基類 
{
    T data;
    public:
        void print()
        {
            cout<<data<<endl;
        }
};

class Derived:public TBase<int>     //從模板類繼承,普通類 
{
};

int main()
{
    Derived d;
    d.print();
}

0

程序9-12 類模板繼承普通類

#include <iostream>
using namespace std;
class TBase     //基類鲜滩,普通類 
{
    int k;
    public:
        void print()
        {
            cout<<"TBase::"<<k<<endl;
        }
};

template<class T>
class TDerived:public TBase     //派生類伴鳖,類模板 
{
    T data;
    public:
        void setData(T x)
        {
            data = x;
        }
        void print()
        {
            TBase::print();
            cout<<"TDerived::"<<data<<endl;
        }
};

int main()
{
    TDerived<string> d;
    d.setData("2019");
    d.print();
}

TBase::1
TDerived::2019

程序9-13 類模板繼承類模板

#include <iostream>
using namespace std;

template<class T>
class TBase     //類模板 
{
     T data1;
     public:
        void print()
        {
            cout<<"TBase::"<<data1<<endl;
        }
};

template <class T1,class T2>
class TDerived:public TBase<T1>     //派生類,類模板 
{
    T2 data2;
    public:
        void print()
        {
            TBase<T1>::print();
            cout<<"TDerived::"<<data2<<endl;
        }
};

int main()
{
    TDerived<int,int> d;
    d.print();
    TDerived<string,string> d2;
    d2.print();
}

TBase::0
TDerived::0
TBase::
TDerived::

程序9-14 類模板繼承模板類

#include <iostream>
using namespace std;

template<class T>
class TBase
{
    T data1;
    public:
        void print()
        {
            cout<<"TBase::"<<data1<<endl;
        } 
};

template <class T2>
class TDerived:public TBase<int>
{
    T2 data2;
    public:
        void print()
        {
            TBase<int>::print();
            cout<<"TDerived::"<<data2<<endl;
        }
};

int main()
{
    TDerived<int> d;
    d.print();
    TDerived<string>d2;
    d2.print();
}

TBase::0
TDerived::0
TBase::1
TDerived::
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末徙硅,一起剝皮案震驚了整個濱河市榜聂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嗓蘑,老刑警劉巖须肆,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異桩皿,居然都是意外死亡豌汇,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門泄隔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拒贱,“玉大人,你說我怎么就攤上這事梅尤」袼迹” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵巷燥,是天一觀的道長赡盘。 經(jīng)常有香客問我,道長缰揪,這世上最難降的妖魔是什么陨享? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮钝腺,結果婚禮上抛姑,老公的妹妹穿的比我還像新娘。我一直安慰自己艳狐,他們只是感情好定硝,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著毫目,像睡著了一般蔬啡。 火紅的嫁衣襯著肌膚如雪诲侮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天箱蟆,我揣著相機與錄音沟绪,去河邊找鬼。 笑死空猜,一個胖子當著我的面吹牛绽慈,可吹牛的內容都是我干的。 我是一名探鬼主播辈毯,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坝疼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漓摩?” 一聲冷哼從身側響起裙士,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤入客,失蹤者是張志新(化名)和其女友劉穎管毙,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體桌硫,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡夭咬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了铆隘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卓舵。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖膀钠,靈堂內的尸體忽然破棺而出掏湾,到底是詐尸還是另有隱情,我是刑警寧澤肿嘲,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布融击,位于F島的核電站,受9級特大地震影響雳窟,放射性物質發(fā)生泄漏尊浪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一封救、第九天 我趴在偏房一處隱蔽的房頂上張望拇涤。 院中可真熱鬧,春花似錦誉结、人聲如沸鹅士。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掉盅。三九已至嘱朽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間怔接,已是汗流浹背搪泳。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扼脐,地道東北人岸军。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像瓦侮,于是被迫代替她去往敵國和親艰赞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內容