最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解C++模板如何實現(xiàn)多態(tài)思想

 更新時間:2023年03月17日 14:22:50   作者:余識-  
這篇文章主要為大家詳細介紹了C++模板如何實現(xiàn)多態(tài)的相關資料,文中的示例代碼講解詳細,對我們深入了解C++有一定的幫助,感興趣的可以了解一下

一、模板與多態(tài)基礎

再進一步了解如何用模板來實現(xiàn)多態(tài)前,我們還是來看一看這兩個概念的基礎理解

1.模板

首先是模板,其主要用途在于讓我們程序員少寫代碼

比如像下面兩個函數(shù)類似的一系列函數(shù):

int add(int a, int b) {
    return a + b;
}
double add(double a, double b) {
    return a + b;
}

就可以用模板簡寫為:

template<class T>
T add(T a, T b) {
    return a + b;
}

使用的方式如下:

    add<int>(1,3);
    add<double>(1.1, 3.4);
    add<char>('s','a');

但由于C++編譯器可以自動推斷參數(shù)類型,所以中間的<int>是可以省略的

這里要注意一個非常重要的問題,雖然我們只寫了一個模板函數(shù),但實際上并不止有一個函數(shù)

比如這里我們用了三種類型的add函數(shù),那么編譯器就會為我們分別生成三個函數(shù)

也就是說,這是編譯器根據(jù)我們寫的模板。幫我們自動生成的函數(shù)

進一步來說,模板是完全給編譯器看的,并不會參與到最終的可執(zhí)行文件中

上面這一點便是模板的精髓!

為了更加直觀的理解,我們來看一下最終生成的三個函數(shù)的內(nèi)存地址:

#include<iostream>
template<class T>
T add(T a, T b) {
	return a + b;
}

int main() {
	printf("%p\n", add<int>);
	printf("%p\n", add<double>);
	printf("%p\n", add<char>);
}

這樣我們就能實際的看到最終確實是生成了三個函數(shù),因為三個函數(shù)的地址完全不同,分別就代表著三個版本的add函數(shù)

總結(jié)來說就是,模板并沒有減少最終的代碼量,它僅僅只是減少了我們程序員需要寫的代碼量

并且這個過程是在編譯期間就完成了的,這一點很重要!

之所以要用模板來實現(xiàn)多態(tài),就是看重了它是在編譯期間就完成的,而不會去影響最終的可執(zhí)行文件的執(zhí)行時間、大小

2.多態(tài)

然后便是多態(tài)了,多態(tài)是類中一個很重要的概念,其主要用途就是使得函數(shù)接口統(tǒng)一化

比如下面這段代碼:

#include <iostream> 
using namespace std;
class A {
public:
    virtual void area() {
        cout << "這是基類A" << endl;
    }
};
class B : public A {
public:
    void area()
    {
        cout << "這是子類B" << endl;
    }
};
class C : public A {
public:
    void area()
    {
        cout << "這是子類C" << endl;
    }
};
// 程序的主函數(shù)
int main()
{
    A* a;
    a = new B();
    a->area();
    a = new C();
    a->area();
    return 0;
}

邏輯并不復雜,就是B,C兩個類都繼承于A,

并且在基類中我們用到了關鍵字virtual 定義area為虛函數(shù),還在兩個子類里面都分別重寫了這個函數(shù)

因為B,C類都繼承于A類,所以我們可以用A類指針來接收B,C對象

從占用內(nèi)存上考慮,子類是繼承父類的,所以子類所占用的內(nèi)存量肯定大于或等于父類占用內(nèi)存,那么子類申請一塊內(nèi)存,賦值給父類的指針,父類就不可能會內(nèi)存訪問越界,而反過來,如果用子類指針存儲父類對象,由于子類訪問的內(nèi)存大于等于父類,就可能造成內(nèi)存訪問越界,因此一般禁止這樣使用

此時我們發(fā)現(xiàn),我們只用了一個A調(diào)用同一個函數(shù)area,卻可以完成兩個類的調(diào)用!

所以很多時候,當我們使用別人的提供給我們的類時,只要知道了它的父類有哪些函數(shù),那么其子類就必然有對應的函數(shù)

這可以極大方便類的管理、升級以及使用

雖然它的好處很多,但同樣也有壞處,那就是它是動態(tài)綁定函數(shù)的,依靠了一個叫做虛函數(shù)表的東西,導致其內(nèi)存占用更大,運行時間更長

比如上面的代碼我們就可以在調(diào)試窗口中看到其虛函數(shù)表:

就是這個名為 _vfptr的變量名稱,他就是指向虛函數(shù)表的函數(shù)指針,而虛函數(shù)表中就存有我們的虛函數(shù)

父類指針想要正確使用子類重寫的函數(shù),就必須要在這個虛函數(shù)表中進行遍歷查詢對應的函數(shù)地址

所以一旦你的類中有虛函數(shù),那么你的類就肯定會多出一個指針大小的內(nèi)存用于存儲虛函數(shù)表的地址,并且最終生成的可執(zhí)行文件也會變大很多字節(jié)

這取決于你的虛函數(shù)個數(shù),每多一個虛函數(shù),那么虛函數(shù)表就需要多一個指針大小的內(nèi)存來存儲

如果依舊不太懂的,可以自行在瀏覽器中搜索一下,有很多優(yōu)秀的文章對此有解釋

總結(jié)來說就是:使用傳統(tǒng)類的多態(tài)特性,會導致程序效率變低,最終生成的可執(zhí)行文件體積變大

原因就是它生成了虛函數(shù)表、虛函數(shù)指針,在程序運行過程中執(zhí)行查詢函數(shù)的操作

MFC就是因為大量使用的這種多態(tài),公共控件都繼承于基本窗口類,一般都有數(shù)十上百個虛函數(shù),所以這就導致即使你什么都沒干,一個MFC程序都至少有數(shù)兆大小,并且運行效率還較低

二、模板實現(xiàn)多態(tài)

了解了上面所說的兩個基本概念的優(yōu)缺點之后,現(xiàn)在我們就可以來到如何使用模板來實現(xiàn)多態(tài)了

因為模板就是編譯期間就完成的操作,如果讓模板來實現(xiàn)多態(tài),那么就不存在運行期間去遍歷虛函數(shù)表來找對應的函數(shù),也不需要開辟一個虛函數(shù)表來存儲虛函數(shù)地址

既能節(jié)約內(nèi)存,又能提高程序運行效率,是不是非常的完美!

下面我們就來看一看模板實現(xiàn)多態(tài)的基本流程

#include <iostream> 
using namespace std;
template<class T>
class A {
public:
    void Show() {
        T* p=static_cast<T*>(this);
        p->area();
    }
    void area() {
        cout << "這是基類A" << endl;
    }
};
class B : public A<B> {
public:
    void area()
    {
        cout << "這是子類B" << endl;
    }
};
class C : public A<C> {
public:
    void area()
    {
        cout << "這是子類C" << endl;
    }
};
// 程序的主函數(shù)
int main()
{
    B b;
    b.Show();
    C c;
    c.Show();
    return 0;
}

這里同樣是B,C兩個類都繼承自A類,但不同點就在于A類帶了一個模板變量

所以B,C類在繼承A的時候,就需要將自己這個類型傳遞進去

此時三個類都寫了area函數(shù),但只有基類寫了show方法對吧

但由于B,C類都是繼承自A類,所以它們其實也已經(jīng)含有了show方法

然后便是最重要的一步,在基類的show方法中,我將this指針轉(zhuǎn)化為T類型指針

static_cast與強制轉(zhuǎn)化基本等價,唯一很大一點的區(qū)別就是,強制轉(zhuǎn)換可以任意使用,比如B沒有繼承自A類,強制轉(zhuǎn)換仍然可以將兩者指針進行轉(zhuǎn)換,而static_cast無法轉(zhuǎn)換兩個毫不相干的東西,這樣就保證了傳入的類型是繼承自基類的,否則編譯會直接報錯

此時這里的p指針

T* p=static_cast<T*>(this);

實際就轉(zhuǎn)化為了調(diào)用者的指針,以B舉例子:

B b;
b.Show(); //調(diào)用Show方法后,完成了指針的轉(zhuǎn)換,指代的B,那么B調(diào)用area函數(shù),也就是調(diào)用自己重寫的area函數(shù)

如果現(xiàn)在再多出一個子類D繼承于A,但里面什么都沒有:

class D : A<D>{
}

那么當你使用D時:

D d;
d.Show(); //將指針轉(zhuǎn)換為D類型,由于D類型沒有重寫area方法,所以將調(diào)用繼承下來的基類area方法

同樣是一個show函數(shù),能夠卻能根據(jù)情況選擇出不同的函數(shù)調(diào)用,而且還是在編譯期間就完成了的

這便是模板實現(xiàn)多態(tài)的基本原理

三、實際應用

由于上面說的都是實現(xiàn)原理,例子比較奇怪,下面我們來直接看一看ATL中的代碼:

WTL是基于ATL之上開發(fā)的,而ATL庫則是vs開發(fā)環(huán)境中自帶,WTL庫需要自己去下載

可以輸入以下代碼

#include<atlwin.h>
class MyWindow :public CWindowImpl<MyWindow> 
{

};

然后右鍵速覽CWindowImpl類,接著在跳出的文件中搜索static_cast:

就能看到很多像上圖這樣的調(diào)用

1.先將this指針還原為子類

2.然后再調(diào)用對應的函數(shù)

3.如果子類重寫了這個函數(shù),那么就調(diào)用子類的函數(shù),否則就調(diào)用父類的函數(shù)

當然這并不完全如此,比如上圖中的那一出,是將其轉(zhuǎn)化為子類后,傳給某個函數(shù)進行處理

不過總體邏輯是一致的:在父類中操作子類,以實現(xiàn)靜態(tài)多態(tài)的目的

到此這篇關于深入理解C++模板如何實現(xiàn)多態(tài)思想的文章就介紹到這了,更多相關C++模板 多態(tài)思想內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • tinyxml 常用的C++ XML解析器非常優(yōu)秀

    tinyxml 常用的C++ XML解析器非常優(yōu)秀

    讀取和設置xml配置文件是最常用的操作,試用了幾個C++的XML解析器,個人感覺TinyXML是使用起來最舒服的,因為它的API接口和Java的十分類似,面向?qū)ο笮院芎?/div> 2012-11-11
  • C語言實現(xiàn)簡易掃雷程序

    C語言實現(xiàn)簡易掃雷程序

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)簡易掃雷程序,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C++ STL vector的模擬實現(xiàn)

    C++ STL vector的模擬實現(xiàn)

    這篇文章主要介紹了C++ STL vector的模擬實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • C、C++線性表基本操作的詳細介紹

    C、C++線性表基本操作的詳細介紹

    這篇文章主要給大家介紹了關于C、C++線性表基本操作的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-11-11
  • 深入理解數(shù)組指針與指針數(shù)組的區(qū)別

    深入理解數(shù)組指針與指針數(shù)組的區(qū)別

    本篇文章是對數(shù)組指針與指針數(shù)組的區(qū)別進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • C語言實現(xiàn)三子棋

    C語言實現(xiàn)三子棋

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)三子棋游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-01-01
  • Opencv基于文字檢測去圖片水印的實現(xiàn)示例

    Opencv基于文字檢測去圖片水印的實現(xiàn)示例

    去水印是個麻煩事,本文就來介紹一種方法Opencv基于文字檢測去圖片水印的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • C語言中 type *(0)的具體使用

    C語言中 type *(0)的具體使用

    表達式?type * (0)?在 C/C++ 編程中是一個常見的技巧,通常用于內(nèi)核編程和一些系統(tǒng)編程場景中,本文主要介紹了C語言中 type *(0)的具體使用,感興趣的可以了解一下
    2024-08-08
  • C語言內(nèi)嵌匯編API內(nèi)存搜索引擎實例

    C語言內(nèi)嵌匯編API內(nèi)存搜索引擎實例

    這篇文章主要介紹了C語言內(nèi)嵌匯編API內(nèi)存搜索引擎實例,涉及匯編語言與內(nèi)存相關操作,需要的朋友可以參考下
    2014-10-10
  • C++簡明圖解分析淺拷貝與深拷貝

    C++簡明圖解分析淺拷貝與深拷貝

    在c++中,深拷貝和淺拷貝也算是一個難點,特別是對于初學者來說,往往在不知道兩者區(qū)別的情況下而錯誤的使用了淺拷貝,從而導致了野指針之類的問題,但是又因為缺少理解所以很難定位到問題所在
    2022-06-06

最新評論

南宫市| 南京市| 嘉禾县| 鲁甸县| 高雄县| 广南县| 美姑县| 大连市| 昌江| 利川市| 正镶白旗| 呼伦贝尔市| 和硕县| 郸城县| 乌什县| 航空| 会东县| 正安县| 蒲城县| 五原县| 东阳市| 金山区| 迁西县| 黎城县| 繁昌县| 承德县| 高尔夫| 柏乡县| 平安县| 兴文县| 绍兴县| 古交市| 洛扎县| 孝昌县| 扎兰屯市| 繁峙县| 高雄县| 将乐县| 蒲城县| 霍邱县| 额敏县|