欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++設(shè)計(jì)模式之CRTP的使用

 更新時(shí)間:2023年10月18日 14:09:34   作者:思想覺悟  
CRTP全稱是curious?recurring?template?pattern,即奇異遞歸模版模式,是一種c++的設(shè)計(jì)模式,精巧地結(jié)合了繼承和模板編程的技術(shù),下面就跟隨小編一起來(lái)學(xué)習(xí)一下CRTP的使用吧

什么是CRTP

CRTP全稱是curious recurring template pattern,即奇異遞歸模版模式,是一種c++的設(shè)計(jì)模式,精巧地結(jié)合了繼承和模板編程的技術(shù)??梢杂脕?lái)給c++的class提供額外功能、實(shí)現(xiàn)靜態(tài)多態(tài)等。

在CRTP之前只聽說(shuō)C++通過(guò)指針實(shí)現(xiàn)了動(dòng)態(tài)多態(tài),現(xiàn)在居然搞出了一個(gè)靜態(tài)多態(tài)的東西出來(lái)?不得不感慨C++真是一門高深莫測(cè)的語(yǔ)言...

動(dòng)態(tài)多態(tài)

在了解靜態(tài)多態(tài)之前我們先來(lái)回顧一下動(dòng)態(tài)多態(tài),C++ 通過(guò)類的繼承與虛函數(shù)的動(dòng)態(tài)綁定,實(shí)現(xiàn)了多態(tài)。這種特性,使得我們能夠用基類的指針,訪問(wèn)子類的實(shí)例。

#include <iostream>

class Animal{
public:
    // 注意需要添加virtual關(guān)鍵字
    virtual void run(){
        std::cout << "Animal run" << std::endl;
    }
};

class Cat:public Animal{
public:
    void run() override{
        std::cout << "Cat run" << std::endl;
    }
};

int main() {
    std::vector<Animal> animalVec;
    animalVec.emplace_back(Animal());
    // 非指針的形式,其實(shí)內(nèi)部調(diào)用的還是Animal的run
    animalVec.emplace_back(Cat());
    for (auto animal:animalVec) {
        animal.run();
    }
    // 動(dòng)態(tài)多態(tài)需要通過(guò)指針的形式實(shí)現(xiàn)
    std::vector<Animal*> animalVecPtr;
    animalVecPtr.push_back(new Animal());
    animalVecPtr.push_back(new Cat());
    for (auto animal:animalVecPtr) {
        animal->run();
    }
    return 0;
}

CRTP的一個(gè)重要功能就是用來(lái)實(shí)現(xiàn)靜態(tài)多態(tài),CRTP在編譯階段就將子類類型以模版的形式傳遞到父類,以便在編譯階段實(shí)現(xiàn)多態(tài)性,這就是靜態(tài)多態(tài)。

既然有了動(dòng)態(tài)多態(tài),為什么還需要靜態(tài)多態(tài)呢?答案是精益求精,為了效率而生...

我們知道動(dòng)態(tài)多態(tài)是基于虛函數(shù)的形式在運(yùn)行時(shí)進(jìn)行動(dòng)態(tài)綁定的,因此每次運(yùn)行時(shí)都需要查詢虛函數(shù)表,所以動(dòng)態(tài)綁定會(huì)降低程序的執(zhí)行效率。 為了兼顧多態(tài)與效率,就提出了CRTP。

CRTP的使用

我們先來(lái)看看在cppreference中是如何使用CRTP的

下面我們依然使用上面Animal的例子通過(guò)CRTP的方式實(shí)現(xiàn)靜態(tài)多態(tài)。

首先我們按照官方的例子,依瓢畫葫蘆:

#include <iostream>

template  < class T >
class Animal{
public:
    virtual ~Animal(){

    };
    // CRTP這里已經(jīng)不需要使用virtual關(guān)鍵字了
     void run(){
        (static_cast<T*>(this))->run();
    }
};

class Cat:public Animal<Cat>{
public:
    void run(){
        std::cout << "Cat run" << std::endl;
    }
};

class Dog:public Animal<Dog>{
public:
    void run(){
        std::cout << "Dog run" << std::endl;
    }
};

int main() {
    Animal<Cat>* cat = new Cat;
    cat->run();
    delete cat;
    Animal<Dog>* dog = new Dog;
    dog->run();
    delete dog;
    return 0;
}

程序運(yùn)行起來(lái)后打印如下:

可以發(fā)現(xiàn)通過(guò)CRTP我們不使用關(guān)鍵字virtual也能實(shí)現(xiàn)了通過(guò)父類指針調(diào)用子類方法效果,這就是靜態(tài)多態(tài)的優(yōu)點(diǎn),它比動(dòng)態(tài)多態(tài)更高效,更安全。

通過(guò)上面的例子我們總結(jié)一下使用CRTP的三個(gè)重要步驟:

  • 繼承自模版類,因?yàn)橛玫搅死^承,因此析構(gòu)函數(shù)需要用virtual修飾,以避免內(nèi)存泄露。
  • 子類將自身通過(guò)模板參數(shù)傳遞給父類。
  • 父類通過(guò)static_cast關(guān)鍵字將模板參數(shù)靜態(tài)轉(zhuǎn)化成子類,然后調(diào)用子類的鴨子模型方法。

一般來(lái)說(shuō)將父類轉(zhuǎn)換成子類一般使用的是dynamic_cast,而CRTP是在編譯期間就已經(jīng)明確知道了子類的具體類型,因此直接使用static_cast更為高效。 這也正是CRTP這種設(shè)計(jì)的一大精髓。

通過(guò)仔細(xì)對(duì)比我們動(dòng)態(tài)多態(tài)和靜態(tài)多態(tài)的兩個(gè)例子我們發(fā)現(xiàn)還是有點(diǎn)不一樣的,我們?cè)趧?dòng)態(tài)多態(tài)中將Animal的指針添加到了std::vector中去,那么我們的CRTP能否也這樣做呢? 我們來(lái)試一下:

#include <iostream>

template<class T>
class Animal {
public:
    virtual ~Animal() {

    };
    // CRTP這里已經(jīng)不需要使用virtual關(guān)鍵字了
    void run() {
        (static_cast<T *>(this))->run();
    }
};

class Cat : public Animal<Cat> {
public:
    void run() {
        std::cout << "Cat run" << std::endl;
    }
};

class Dog : public Animal<Dog> {
public:
    void run() {
        std::cout << "Dog run" << std::endl;
    }
};

int main() {
    std::vector<Animal<Cat>*> animalVec;
    animalVec.emplace_back(new Cat());
    // 報(bào)錯(cuò)了,因?yàn)関ector存放的數(shù)據(jù)類型是Animal<Cat>
    animalVec.emplace_back(new Dog());
    for (auto animal: animalVec) {
        animal->run();
    }
    return 0;
}

我們發(fā)現(xiàn)報(bào)錯(cuò)了,因?yàn)锳nimal和Animal不是同樣的數(shù)據(jù)類型,不能同時(shí)放入同一個(gè)vector中去。 既然問(wèn)題的根源是他們不是同樣的數(shù)據(jù)類型,那么我們將它們變成同樣的數(shù)據(jù)類型不就是行了嗎?那么怎么把它們變成同樣的數(shù)據(jù)類型呢?

讓它們繼承一個(gè)共同的基類即可。這樣就是動(dòng)態(tài)多態(tài)與靜態(tài)多態(tài)結(jié)合使用的例子了。

實(shí)例代碼如下:

#include <iostream>

class BaseAnimal {
public:
    virtual ~BaseAnimal() {

    };

    virtual void run() = 0;
};

template<class T>
class Animal: public BaseAnimal{
public:
    virtual ~Animal() {

    };
    // CRTP這里已經(jīng)不需要使用virtual關(guān)鍵字了
    void run() override{
        (static_cast<T *>(this))->run();
    }
};

class Cat : public Animal<Cat> {
public:
    void run() override {
        std::cout << "Cat run" << std::endl;
    }
};

class Dog : public Animal<Dog> {
public:
    void run() override {
        std::cout << "Dog run" << std::endl;
    }
};

int main() {
    std::vector<BaseAnimal*> animalVec;
    animalVec.emplace_back(new Cat());
    // 報(bào)錯(cuò)了,因?yàn)関ector存放的數(shù)據(jù)類型是Animal<Cat>
    animalVec.emplace_back(new Dog());
    for (auto animal: animalVec) {
        animal->run();
    }
    return 0;
}

這樣一來(lái),我們通過(guò)CRTP與虛函數(shù)結(jié)合,即保留了動(dòng)態(tài)多態(tài)的各種特性,也減少了部分虛函數(shù)的查找開銷。

到此這篇關(guān)于C++設(shè)計(jì)模式之CRTP的使用的文章就介紹到這了,更多相關(guān)C++設(shè)計(jì)模式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C語(yǔ)言詳解判斷相同樹案例分析

    C語(yǔ)言詳解判斷相同樹案例分析

    這篇文章主要介紹了用C語(yǔ)言檢查兩棵樹是否相同,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2022-04-04
  • C語(yǔ)言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì)

    C語(yǔ)言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)通訊錄系統(tǒng)課程設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • Qt編寫顯示密碼強(qiáng)度的控件

    Qt編寫顯示密碼強(qiáng)度的控件

    這篇文章主要為大家詳細(xì)介紹了Qt編寫顯示密碼強(qiáng)度的控件,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • 如何查看進(jìn)程實(shí)際的內(nèi)存占用情況詳解

    如何查看進(jìn)程實(shí)際的內(nèi)存占用情況詳解

    本篇文章是對(duì)如何查看進(jìn)程實(shí)際的內(nèi)存占用情況進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • 嵌入式C語(yǔ)言查表法在項(xiàng)目中的應(yīng)用

    嵌入式C語(yǔ)言查表法在項(xiàng)目中的應(yīng)用

    今天小編就為大家分享一篇關(guān)于嵌入式C語(yǔ)言查表法在項(xiàng)目中的應(yīng)用,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • C語(yǔ)言中的函數(shù)指針學(xué)習(xí)筆記

    C語(yǔ)言中的函數(shù)指針學(xué)習(xí)筆記

    這篇文章主要介紹了C語(yǔ)言中的函數(shù)指針的一些學(xué)習(xí)知識(shí)點(diǎn)記錄,文中作者整理了一些比較interesting的函數(shù)指針用法,需要的朋友可以參考下
    2016-04-04
  • C++控制臺(tái)實(shí)現(xiàn)俄羅斯方塊游戲

    C++控制臺(tái)實(shí)現(xiàn)俄羅斯方塊游戲

    這篇文章主要為大家詳細(xì)介紹了C++控制臺(tái)實(shí)現(xiàn)俄羅斯方塊游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • 關(guān)于C++中的友元函數(shù)的一些總結(jié)

    關(guān)于C++中的友元函數(shù)的一些總結(jié)

    以下是對(duì)C++中的友元函數(shù)進(jìn)行了詳細(xì)的總結(jié)介紹,需要的朋友可以過(guò)來(lái)參考下
    2013-09-09
  • C++的靜態(tài)類型檢查詳解

    C++的靜態(tài)類型檢查詳解

    這篇文章主要為大家詳細(xì)介紹了C++的靜態(tài)類型檢查,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • VSCode 配置C++開發(fā)環(huán)境的方法步驟

    VSCode 配置C++開發(fā)環(huán)境的方法步驟

    這篇文章主要介紹了VSCode 配置C++開發(fā)環(huán)境的方法步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03

最新評(píng)論