色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

虛函數,C++開發者如何有效利用

Linux愛好者 ? 來源:Linux愛好者 ? 2023-02-11 09:39 ? 次閱讀

什么是虛函數?

虛函數是基類中聲明的成員函數,且使用者期望在派生類中將其重新定義。那么,在C++ 中,什么是虛函數呢?C++ 中,通常將虛函數用于實現運行時多態,該特性由 C++ 提供,適用于面向對象編程我們將在下文更為詳細地討論運行時多態。不論函數調用所使用的指針或引用類型如何,虛函數最為重要的工作是確保函數調用正確

1虛函數的使用規則

C++虛函數必須遵循幾個關鍵規則:

  • 在基類中使用virtual關鍵詞來聲明函數

  • 虛函數不能為靜態函數

  • 為實現運行時多態,應使用指針或引用來訪問虛擬函數

  • 對于基類和派生類而言,此類函數的原型應該相同(允許使用協變式返回類型,我們將在下文進行討論)

  • 如果基類中含有虛函數,則應該使用虛擬析構函數,防止析構函數調用錯誤

2 用 C++ 運行虛函數的示例

虛函數在C++ 中的運行情況:

class Pet {
public:
    virtual ~Pet() {}
    virtual void make_sound() const = 0;
};


class Dog: public Pet {
public:
    virtual void make_sound() const override {
        std::cout << "raf raf
";
    }
};


class Cat: public Pet {
public:
    virtual void make_sound() const override {
        std::cout << "mewo
";
    }
};


int main() {
    Cat mitzi;
    Dog roxy;
    Pet *pets[] = {&mitzi, &roxy};
    for(auto pPet: pets) {
        pPet->make_sound();
    }
}
解釋一下上述示例。Pet 這是一個通用基類。但是我們仍然希望存在一個 make_sound 函數,這樣,我們就能在不知道 pet 類型的情況下,在 pet 上調用 make_sound。僅在進行編譯時,我們才能知道 pet 類型。因此,我們在基類中聲明虛函數 make_sound,用 =0 來將其表示為由派生類實現的純虛函數。然后,再由 Dog 和 Cat 來真正實現該函數。實現函數期間,我們添加關鍵詞 override,這樣,編譯器就能確保函數簽名與基類中的簽名相匹配。在 main 中,我們可以在 Pet 指針上調用 make_sound,而無需在編譯時知道該指針指向哪種 pet。我們會在運行時,根據實際存在的對象,實現所需函數。我們必須要強調,這是一個非常簡單的示例。我們也有其他解決方案應對這一簡單示例(例如,為 pet’s sound 持有數據成員,并避免使用虛函數)。但我們想要展示虛函數的實現過程,因此不對其他解決方案進行額外展示。通常情況下,會使用虛函數為派生類中的不同行為建模,而相應行為不能用簡單數據成員來建模。 3 協變式返回類型我們提到過,若要實現虛函數,派生類函數的簽名必須與基類中的簽名相匹配。唯一允許的區別是在返回類型上,只要派生類的返回類型是基類返回的派生類型即可。讓我們看看下面的示例:
class PetFactory {
public:
    virtual ~PetFactory() {}
    virtual Pet* create() const = 0;
} 


class DogFactory: public PetFactory {
public:
    virtual Dog* create() const override {
        return new Dog();
    }
}; 


class CatFactory: public PetFactory {
public:
    virtual Cat* create() const override {
        return new Cat();
    }
};


int main() {
    std::vector pets;
    DogFactory df;
    CatFactory cf;
    PetFactory* petFactory[] = {&df, &cf};
    for(auto factory: petFactory) {
        pets.push_back(factory->create());
    }
    for(auto pPet: pets) {
        pPet->make_sound();
    }
    for(auto pPet: pets) {
        delete pPet;
    }
}
在上述示例中,PetFactory 創建函數僅能知道它可以返回 Pet*,但使用協變式返回類型,DogFactory 和 CatFactory 則能知道更為具體的內容,這種虛函數的實現方式仍然行之有效。

現在,如果您已經花費時間研究過 C++,可能會注意到,不需要由虛函數來重新定義派生類中的基函數。但存在這樣的巨大區別,使得虛函數不可或缺:虛函數覆寫基類函數,從而實現運行時多態。從本質上講,多態指一個函數或對象以不同方式執行的能力,具體情況視使用方式而定。這屬于面向對象編程的關鍵特性——結合其他眾多特性,使得 C++ 作為編程語言而有別于 C 語言。

1 代碼更為靈活、更為通用這是貫穿所有多態程序的主要優點:根據運行時已知的調用對象,通過允許以不同方式執行函數調用,能使程序更為靈活而通用。如此一來,運行時多態便能從真正意義上使您的代碼反映現實——特別是各場景中的對象(或人、動物、形狀)并不總是以相同方式執行。 2 代碼可復用通過使用虛函數,我們可以將只應實現一次的通用操作和不同子類中可能有所不同的具體細節區分開來。試想以下示例:如果我們希望實現 prism 類層次結構,則需要在各派生類中分別計算基面積,但可以使用派生類實現基面積計算,從而在基類中實現體積函數。實現代碼如下:
class Prism {
    double height;
public:
    virtual ~Prism() {}
    virtual double baseArea() const = 0;
    double volume() const {
        return height * baseArea();
    }
    // ...
};


class Cylinder: public Prism {
    double radius;
public:
    double baseArea() const override {
         return radius * radius * std::pi
    }
    // ...
};
3 契約式設計術語“契約式設計”指如果代碼設置有執行設計的契約,會比只通過文檔來執行設計要好得多。虛函數,特別是純虛函數,因其決定了在派生類中以不同方式重新實現特定操作的設計決策,可將其視為契約式設計工具。 虛函數的局限性

虛函數功能極為強大,但它們并非毫無缺點。開始使用虛函數前,您應該注意以下事項:

1 性能

無論是在運行時性能還是在內存方面,虛函數成本都要比普通函數高。

內存部分通常冗余,取決于實現方式,但最為常見的是每個對象都有一個額外內部指針。這并不是什么大問題,除非我們有數以百萬計的小對象,這些小對象的額外指針可能會引起內存問題。

函數的運行時性能成本不是一次跳轉而是兩次跳轉,或者如果可以內聯函數,性能成本就是兩次跳轉而不是零次跳轉。虛函數需要跳轉到虛函數表,再跳轉到函數本身。這種額外跳轉增加了 CPU 指令緩存中指令未準備就緒的概率,因此,這兩次跳轉并非唯一成本。

最后,如果您需要實現多態,與其他替代方案相比,性能方面的額外成本通常也在情理之中。然而,若要將第一個虛函數添加到類中,通常需要考慮額外成本。

2設計問題

繼承,特別是虛函數,會引起設計問題。繼承層次結構設計糟糕可能會導致類膨脹和類之間關系異常。

從構造函數和析構函數調用虛函數的規則也會影響您的設計。從構造函數和析構函數調用的任何虛函數都不是多態函數,這樣一來,有時需要將操作從構造函數轉移到 init 虛擬函數。

為避免糟糕設計,應切記繼承和多態并非是應對任何問題的最佳解決方案。請觀看 Sean Parent 的演講”Inheritance is the Base Class of Evil“,深入了解相關內容。

3 調試,容易出錯

諷刺的是,虛函數面臨的挑戰之一是缺乏彈性。

由于需要遵循調用流程,調試虛函數調用可能會變得稍顯混亂。一般來說,遵循函數調用并不十分困難,但根據對象類型,在遵循隱藏調度方面,仍然需要進行額外工作。調試器會自行糾正錯誤,但決定斷點位置可能會變得更加困難。

至于更容易出錯,在某些情況下,不應調用虛函數的基類實現;而在某些情況下,應在開始時調用,有時也在結束時調用。由于忘記調用基類實現,或是在錯誤的地方、不需要的時候調用,使用虛函數極其容易出錯。

可將其視為契約式設計工具。 虛函數的替代方案1 僅使用數據成員第一種替代方案是嘗試并對基于簡單數據成員的不同行為進行建模。如果不同類型的唯一區別是 sound,那就將其轉換為數據成員,在構造時進行初始化,這樣就沒有問題了。但在許多情況下,行為更加復雜,需要不同的實現方式。 2 變體另一種方案是使用 std::variant 和 std::visit,特別是待支持的不同類型已知,且列表不會太長時,二者可能相關。您可以點擊此處和此處閱讀更多關于該方案的信息 3 函數式編程您可以傳遞待執行的操作,將其作為函數對象的 lambda,或者作為舊有 C 樣式的函數指針,隨后對其進行建模,而無需在類層次結構中對不同操作進行建模。通過該方法,您能將數據模型和可能想要執行的操作區分開來,這帶來了極高靈活性。 4 靜態多態靜態多態是一種基于模板的方法,用于獲取多態動態,但基于編譯時已知的實際想要使用的類型。例如,您可能希望代碼同時支持 UDPConnection 和 TCPConnection,但在編譯時,您可能想要知道使用 UDPConnection 或 TCPConnection 的具體流程。基于模板的靜態多態可以實現更佳性能。一些替代技術可能會導致項目編譯時間變長。我們認為,特別是當您使用 Incredibuild 來加速構建時,這不會影響您的決策設計。首先選擇合適的設計方案,然后使用正確工具來縮減編譯時間即可。 用 Incredibuild 加速您的 C++ 虛函數如果您想在不嚴重拖累編譯速度和構建進程的情況下,從虛擬函數中受益,您就需要強大的計算能力作為后援。Incredibuild 能夠做到這一點。通過在虛擬機在本地網絡上分配編譯任務,Incredibuild 從根本上加快了 C++ 的編譯速度。此外,Incredibuild 能與時下主流編譯器和構建系統無縫集成,包括 Visual Studio、Qt Creator 和 Clang。如此一來,虛函數便能具備極高的靈活性和效率,而無需花費時間來等待代碼編譯。。首先選擇合適的設計方案,然后使用正確工具來縮減編譯時間即可。 總 結 1. 什么是 C++ 的虛函數?虛擬函數是基類中聲明的成員函數,將在派生類中重新定義。在 C++ 中,使用虛函數來實現運行時多態。2. 虛函數存在哪些問題?在運行時性能和內存使用方面,相比于普通函數,虛擬函數會造成更多影響。此外,虛擬函數會產生基于繼承層次結構的設計問題,導致類膨脹和關系異常。最后,虛擬函數由于存在函數調用問題,往往難以進行調試。由于調用順序的不可預測性,使用虛擬函數更容易引發錯誤。3. 在 C++ 中,虛函數有何替代方案?是的,為了實現更好的設計或者是獲得更佳的性能,您可能要考慮一些替代方案。但鑒于 C++ 程序員普遍使用虛函數,您應將其視為工具包內的一項工具,必要時加以使用。如果您選擇了另一種替代方案,比如基于模板的靜態多態,切勿讓較長的編譯時間影響您的設計方案。確保選用合適的工具來加速構建進程,如果您沒有使用 Incredibuild,請了解我們的解決方案,看看 Incredibuild 在減少編譯時間方面可實現的驚人效果。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • C++
    C++
    +關注

    關注

    22

    文章

    2108

    瀏覽量

    73622
  • 虛函數
    +關注

    關注

    0

    文章

    8

    瀏覽量

    1698

原文標題:虛函數,C++開發者如何有效利用?

文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    C++函數virtual詳解

    C++ 中的函數用于解決動態多態問題,函數的作用是允許在派生類中重新定義與積累同名的函數,并
    發表于 09-07 11:27 ?2879次閱讀

    C++函數操作指南(含代碼示例)

    本期博客,我們來介紹C++中的函數,并給出一些實際操作的建議。
    發表于 02-12 10:12 ?673次閱讀

    C++標準編程:函數與內聯

      曾經在討論C++的時候,經常會問到:“函數能被聲明為內聯嗎?”現在,我們幾乎聽不到這個問題了。現在聽到的是:“你不應該使print成為內聯的。聲明一個
    發表于 05-03 11:53

    STM32 C++代碼封裝初探相關資料推薦

    、抽象化。C++是一種天然支持面向對象編程的語言,在C語言的基礎上,C++不僅提供了class關鍵字和類與對象的概念,使開發者可以清晰方便的實現面向對象編程。
    發表于 02-11 06:05

    什么是C++函數? 應該怎么定義? 用途是什么?

    什么是C++函數? 應該怎么定義? 主要用途是什么?
    發表于 11-08 06:58

    C++如何處理內聯函數

    當一個函數是內聯和函數時,會發生代碼替換或使用表調用嗎? 為了弄 清楚內聯和函數,讓我們將
    發表于 11-29 11:59 ?28次下載

    C++程序設計教程之多態性與函數的詳細資料說明

    本文檔詳細介紹的是C++程序設計教程之多態性與函數的詳細資料說明主要資料包括了:1 多態性的概念,2 一個典型的例子,3 函數,4 純
    發表于 03-14 16:39 ?5次下載
    <b class='flag-5'>C++</b>程序設計教程之多態性與<b class='flag-5'>虛</b><b class='flag-5'>函數</b>的詳細資料說明

    如何在中斷C函數中調用C++

    之前,我們在單片機程序開發時都會面對中斷函數。眾所周知的,這個中斷函數肯定是要用C函數來定義的。我在用C
    發表于 05-09 18:17 ?0次下載
    如何在中斷<b class='flag-5'>C</b><b class='flag-5'>函數</b>中調用<b class='flag-5'>C++</b>

    圖文詳解:C++表的剖析

    圖文詳解:C++表的剖析
    的頭像 發表于 06-29 14:23 ?2534次閱讀
    圖文詳解:<b class='flag-5'>C++</b><b class='flag-5'>虛</b>表的剖析

    C++中如何用函數實現多態

    01 — C++函數探索 C++是一門面向對象語言,在C++里運行時多態是由
    的頭像 發表于 09-29 14:18 ?1693次閱讀

    一文詳解函數及其相關知識點

    本期是C++基礎語法分享的第七節,今天給大家來分享一下: (1)析構函數; (2)純函數; (3)
    的頭像 發表于 10-13 10:14 ?7925次閱讀

    華為開發者大會2021_方舟開發有效提升開發效率

    華為開發者大會2021中,重點闡述了方舟開發框架,此框架有效的提升開發效率。
    的頭像 發表于 10-22 15:17 ?1384次閱讀
    華為<b class='flag-5'>開發者</b>大會2021_方舟<b class='flag-5'>開發有效</b>提升<b class='flag-5'>開發</b>效率

    華為開發者大會2021HDCS——為什么要用C++開發HarmonyOS應用

    體驗的未來。 為什么要用C++開發HarmonyOS應用 進步提升設備性能,以降低延遲 ? 運行游戲或物理模擬等計算密集型應用 ? 重復使用您自己或其他開發者C
    的頭像 發表于 10-23 16:13 ?2121次閱讀
    華為<b class='flag-5'>開發者</b>大會2021HDCS——為什么要用<b class='flag-5'>C++</b><b class='flag-5'>開發</b>HarmonyOS應用

    openEuler Summit開發者峰會:iSula+StratoVirt輕量機容器解決方案展示

    openEuler Summit開發者峰會:iSula+StratoVirt輕量機容器解決方案展示
    的頭像 發表于 11-10 10:46 ?1478次閱讀
    openEuler Summit<b class='flag-5'>開發者</b>峰會:iSula+StratoVirt輕量<b class='flag-5'>虛</b>機容器解決方案展示

    深度解析C++中的函數

    函數作為C++的重要特性,讓人又愛又怕,愛它功能強大,但又怕駕馭不好,讓它反咬一口,今天我們用CPU的角度,撕掉語法的偽裝,重新認識一下函數
    的頭像 發表于 02-15 11:14 ?828次閱讀
    深度解析<b class='flag-5'>C++</b>中的<b class='flag-5'>虛</b><b class='flag-5'>函數</b>
    主站蜘蛛池模板: 亚洲色综合中文字幕在线| 趁老师睡着吃她的奶水| 国产精品亚欧美一区二区三区| 欧美日韩亚洲成人| 国产AV无码一二三区视频| 无码观看AAAAAAAA片| 果冻传媒在线观看完整版免费| 偷拍亚洲制服另类无码专区| 国产真实露脸乱子伦| 99re久久热在线播放8| 亚洲精品久久久无码一区二区| 人妻少妇久久久久久97人妻| 老师湿乎乎两半嫩| 国语自产一区第二页| 国产精品久久久久秋霞影视| AV国产乱码一区二区三视频| 一个人日本的视频免费完整版 | 国产成人无码精品久久久免费69| 中国女人内谢69xxxxxx直播| 亚洲一区国产| 亚洲三级黄色片| 一亲二脱三插| 与嫂子同居的日子在线观看| 亚洲日本香蕉视频观看视频| 亚洲伊人网站| 亚洲欭美日韩颜射在线二| 无罩看奶禁18| 学校女性奴sm训练调教| 西西人体一级裸片| 翁公吮她的花蒂和奶水| 污污内射在线观看一区二区少妇 | 中俄两军在日本海等上空战略巡航| 洗濯屋H纯肉动漫在线观看 | 久久精品观看| 精子pk美女| 久久视频在线视频| 美女用手扒开粉嫩的屁股| 老师的玉足高跟鞋满足我| 欧美s00老人| 老湿机一区午夜精品免费福利| 韩国羞羞秘密教学子开车漫书|