C++類模板盒犹,你看我就夠了

1111.jpg

C++中有一個(gè)重要特性,那就是模板類型眨业。類似于Objective-C中的泛型急膀。C++通過(guò)類模板來(lái)實(shí)現(xiàn)泛型支持。

1 基礎(chǔ)的類模板

類模板龄捡,可以定義相同的操作卓嫂,擁有不同數(shù)據(jù)類型的成員屬性。

通常使用template來(lái)聲明聘殖。告訴編譯器晨雳,碰到T不要報(bào)錯(cuò),表示一種泛型.

如下奸腺,聲明一個(gè)普通的類模板:

template <typename T>
class Complex{
    
public:
    //構(gòu)造函數(shù)
    Complex(T a, T b)
    {
        this->a = a;
        this->b = b;
    }
    
    //運(yùn)算符重載
    Complex<T> operator+(Complex &c)
    {
        Complex<T> tmp(this->a+c.a, this->b+c.b);
        return tmp;
    }
        
private:
    T a;
    T b;
}

int main()
{
    //對(duì)象的定義餐禁,必須聲明模板類型,因?yàn)橐峙鋬?nèi)容
    Complex<int> a(10,20);  
    Complex<int> b(20,30);
    Complex<int> c = a + b;
    
    return 0;
}



2 模板類的繼承

在模板類的繼承中突照,需要注意以下兩點(diǎn):

  • 如果父類自定義了構(gòu)造函數(shù)帮非,記得子類要使用構(gòu)造函數(shù)列表來(lái)初始化
  • 繼承的時(shí)候,如果子類不是模板類,則必須指明當(dāng)前的父類的類型喜鼓,因?yàn)橐峙鋬?nèi)存空間
  • 繼承的時(shí)候副砍,如果子類是模板類,要么指定父類的類型庄岖,要么用子類的泛型來(lái)指定父類
template <typename T>
class Parent{
public:
    Parent(T p)
    {
        this->p = p;
    }
    
private:
    T p;
};

//如果子類不是模板類豁翎,需要指明父類的具體類型
class ChildOne:public Parent<int>{
    
public:
    ChildOne(int a,int b):Parent(b)
    {
        this->cone = a;
    }
    
private:
    int cone;
};


//如果子類是模板類,可以用子類的泛型來(lái)表示父類
template <typename T>
class ChildTwo:public Parent<T>{
    
public:
    ChildTwo(T a, T b):Parent<T>(b)
    {
        this->ctwo = a;
    }
    
private:
    T ctwo;
};

3 內(nèi)部聲明定義普通模板函數(shù)和友元模板函數(shù)

普通模板函數(shù)和友元模板函數(shù)隅忿,聲明和定義都寫在類的內(nèi)部心剥,也不會(huì)有什么報(bào)錯(cuò)。正常背桐。

template <typename T>
class Complex {
    
    //友元函數(shù)實(shí)現(xiàn)運(yùn)算符重載
    friend ostream& operator<<(ostream &out, Complex &c)
    {
        out<<c.a << " + " << c.b << "i";
        return out;
    }
    
public:
    Complex(T a, T b)
    {
        this->a = a;
        this->b = b;
    }
    
    //運(yùn)算符重載+
    Complex operator+(Complex &c)
    {
        Complex temp(this->a + c.a, this->b + c.b);
        return temp;
    }
    
    //普通加法函數(shù)
    Complex myAdd(Complex &c1, Complex &c2)
    {
        Complex temp(c1.a + c2.a, c1.b + c2.b);
        return temp;
    }
    
private:
    T a;
    T b;
};

int main()
{
    Complex<int> c1(1,2);
    Complex<int> c2(3,4);
    
    Complex<int> c = c1 + c2;
    
    cout<<c<<endl;
    
    return 0;
}

4 內(nèi)部聲明友元模板函數(shù)+外部定義友元模板函數(shù)

如果普通的模板函數(shù)聲明在內(nèi)的內(nèi)部优烧,定義在類的外部,不管是否處于同一個(gè)文件链峭,就跟普通的函數(shù)一樣畦娄,不會(huì)出現(xiàn)任何錯(cuò)誤提示。但是如果是友元函數(shù)就會(huì)出現(xiàn)報(bào)錯(cuò)弊仪,是因?yàn)橛?code>二次編譯這個(gè)機(jī)制存在熙卡。

4.1 模板類和模板函數(shù)的機(jī)制

在編譯器進(jìn)行編譯的時(shí)候,編譯器會(huì)產(chǎn)生類的模板函數(shù)的聲明励饵,當(dāng)時(shí)實(shí)際確認(rèn)類型后調(diào)用的時(shí)候驳癌,會(huì)根據(jù)調(diào)用的類型進(jìn)行再次幫我們生成對(duì)應(yīng)類型的函數(shù)聲明和定義。我們稱之為二次編譯役听。同樣颓鲜,因?yàn)檫@個(gè)機(jī)制,會(huì)經(jīng)常報(bào)錯(cuò)找不到類的函數(shù)的實(shí)現(xiàn)典予。在模板類的友元函數(shù)外部定義時(shí)甜滨,也會(huì)出現(xiàn)這個(gè)錯(cuò)誤。解決方法是 “ 類的前置聲明和函數(shù)的前置聲明 ”熙参。

按照普通模板函數(shù)的樣式處理友元函數(shù)


#include <iostream>
using namespace std;


template <typename T>
class Complex {
    
    //友元函數(shù)實(shí)現(xiàn)運(yùn)算符重載
    friend ostream& operator<<(ostream &out, Complex<T> &c);
    
public:
    Complex(T a, T b);
    
    //運(yùn)算符重載+
    Complex<T> operator+(Complex<T> &c);
    
    //普通加法函數(shù)
    Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2);
    
private:
    T a;
    T b;
};

//友元函數(shù)的實(shí)現(xiàn)
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c)
{
    out<<c.a << " + " << c.b << "i";
    return out;
}


//函數(shù)的實(shí)現(xiàn)
template <typename T>
Complex<T>::Complex(T a, T b)
{
    this->a = a;
    this->b = b;
}

template <typename T>
Complex<T> Complex<T>::operator+(Complex<T> &c)
{
    Complex temp(this->a + c.a, this->b + c.b);
    return temp;
}

template <typename T>
Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}


int main()
{
    Complex<int> c1(1,2);
    Complex<int> c2(3,4);
    
    Complex<int> c = c1 + c2;
    
    cout<<c<<endl;
    
    return 0;
}



友元函數(shù)的定義寫在類的外部--錯(cuò)誤信息

Undefined symbols for architecture x86_64:
  "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Complex<int>&)", referenced from:
      _main in demo1.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

上面的錯(cuò)誤信息艳吠,就是典型的二次編譯的錯(cuò)誤信息,找不到友元函數(shù)的函數(shù)實(shí)現(xiàn)孽椰。所以昭娩,如果友元模板函數(shù)的定義寫在函數(shù)的外部,需要進(jìn)行類和函數(shù)的前置聲明黍匾,來(lái)讓編譯器找到函數(shù)的實(shí)現(xiàn)

4.2 前置聲明解決二次編譯問(wèn)題
  • 類的前置聲明
  • 友元模板函數(shù)的前置聲明
  • 友元模板函數(shù)聲明需要增加泛型支持
前置聲明.png

5 聲明和定義分別在不同的文件(模板函數(shù)栏渺、模板友元)

類的聲明和實(shí)現(xiàn),分別在不同的文件下锐涯,需要增加一個(gè)hpp文件支持磕诊。或者盡量將模板函數(shù)與模板友元放在一個(gè)文件下。

  • 類的聲明與函數(shù)的聲明寫在.h文件
  • 類的實(shí)現(xiàn)及函數(shù)的實(shí)現(xiàn)寫在.cpp文件
  • 將.cpp文件改成.hpp文件
  • 在主函數(shù)中調(diào)用.hpp文件霎终,而不是引用.h文件

如果碰到.h和.hpp文件都存在的情況下滞磺,引用.hpp文件。

demo2.h文件

存放類的聲明和函數(shù)的聲明

#include <iostream>
using namespace std;

//類的前置聲明
template <typename T>
class Complex;

//友元函數(shù)的聲明
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c);

template <typename T>
class Complex {
    
    //友元函數(shù)實(shí)現(xiàn)運(yùn)算符重載
    friend ostream& operator<< <T> (ostream &out, Complex<T> &c);
    
public:
    Complex(T a, T b);
    
    //運(yùn)算符重載+
    Complex<T> operator+(Complex<T> &c);
    
    //普通加法函數(shù)
    Complex<T> myAdd(Complex<T> &c1, Complex<T> &c2);
    
private:
    T a;
    T b;
};

demo2.hpp文件

包括模板函數(shù)的實(shí)現(xiàn)


#include "demo2.h"

//友元函數(shù)的實(shí)現(xiàn)
template <typename T>
ostream& operator<<(ostream &out, Complex<T> &c)
{
    out<<c.a << " + " << c.b << "i";
    return out;
}


//函數(shù)的實(shí)現(xiàn)
template <typename T>
Complex<T>::Complex(T a, T b)
{
    this->a = a;
    this->b = b;
}

template <typename T>
Complex<T> Complex<T>::operator+(Complex<T> &c)
{
    Complex temp(this->a + c.a, this->b + c.b);
    return temp;
}

template <typename T>
Complex<T> Complex<T>::myAdd(Complex<T> &c1, Complex<T> &c2)
{
    Complex temp(c1.a + c2.a, c1.b + c2.b);
    return temp;
}


main.cpp文件

需要調(diào)用hpp文件


#include <iostream>
using namespace std;
#include "demo2.hpp"


int main()
{
    Complex<int> c1(1,2);
    Complex<int> c2(3,4);
    
    Complex<int> c = c1 + c2;
    
    cout<<c<<endl;
    
    return 0;
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莱褒,一起剝皮案震驚了整個(gè)濱河市击困,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌广凸,老刑警劉巖阅茶,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谅海,居然都是意外死亡脸哀,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門扭吁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撞蜂,“玉大人,你說(shuō)我怎么就攤上這事智末×律悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵系馆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我顽照,道長(zhǎng)由蘑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任代兵,我火速辦了婚禮尼酿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘植影。我一直安慰自己裳擎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布思币。 她就那樣靜靜地躺著鹿响,像睡著了一般。 火紅的嫁衣襯著肌膚如雪谷饿。 梳的紋絲不亂的頭發(fā)上惶我,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音博投,去河邊找鬼绸贡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的听怕。 我是一名探鬼主播捧挺,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼尿瞭!你這毒婦竟也來(lái)了闽烙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤筷厘,失蹤者是張志新(化名)和其女友劉穎鸣峭,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體酥艳,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡摊溶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了充石。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莫换。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖骤铃,靈堂內(nèi)的尸體忽然破棺而出拉岁,到底是詐尸還是另有隱情,我是刑警寧澤惰爬,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布喊暖,位于F島的核電站,受9級(jí)特大地震影響撕瞧,放射性物質(zhì)發(fā)生泄漏陵叽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一丛版、第九天 我趴在偏房一處隱蔽的房頂上張望巩掺。 院中可真熱鬧,春花似錦页畦、人聲如沸胖替。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)独令。三九已至,卻和暖如春州胳,著一層夾襖步出監(jiān)牢的瞬間记焊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工栓撞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遍膜,地道東北人碗硬。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像瓢颅,于是被迫代替她去往敵國(guó)和親恩尾。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,511評(píng)論 1 51
  • C++ 模板簡(jiǎn)介 一挽懦、模板 使用模板的目的就是能夠讓程序員編寫與類型無(wú)關(guān)的代碼翰意。 模板是一種對(duì)類型進(jìn)行參數(shù)化的工具...
    MinoyJet閱讀 2,354評(píng)論 0 12
  • 本文博客園地址:http://www.cnblogs.com/xiongxuanwen/p/4290086.htm...
    先之閱讀 836評(píng)論 0 5
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法信柿,內(nèi)部類的語(yǔ)法冀偶,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法渔嚷,線程的語(yǔ)...
    子非魚_t_閱讀 31,598評(píng)論 18 399
  • 問(wèn)題:什么是泛型編程进鸠?泛型編程的代表作品STL是一種高效、泛型形病、可交互操作的軟件組件客年。STL以迭代器 (Itera...
    認(rèn)真學(xué)計(jì)算機(jī)閱讀 2,067評(píng)論 0 8