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

解析C++中的虛擬函數(shù)及其靜態(tài)類型和動(dòng)態(tài)類型

 更新時(shí)間:2016年06月24日 16:20:42   作者:pizzq  
虛擬函數(shù)(Visual Function)亦常被成為虛函數(shù),是C++中的一個(gè)重要特性,本文我們就來解析C++中的虛擬函數(shù)及其靜態(tài)類型和動(dòng)態(tài)類型

虛擬函數(shù)是C++語言引入的一個(gè)很重要的特性,它提供了“動(dòng)態(tài)綁定”機(jī)制,正是這一機(jī)制使得繼承的語義變得相對(duì)明晰。
(1)基類抽象了通用的數(shù)據(jù)及操作,就數(shù)據(jù)而言,如果該數(shù)據(jù)成員在各派生類中都需要用到,那么就需要將其聲明在基類中;就操作而言,如果該操作對(duì)各派生類都有意義,無論其語義是否會(huì)被修改或擴(kuò)展,那么就需要將其聲明在基類中。
(2)有些操作,如果對(duì)于各個(gè)派生類而言,語義保持完全一致,而無需修改或擴(kuò)展,那么這些操作聲明為基類的非虛擬成員函數(shù)。各派生類在聲明為基類的派生類時(shí),默認(rèn)繼承了這些非虛擬成員函數(shù)的聲明/實(shí)現(xiàn),如同默認(rèn)繼承基類的數(shù)據(jù)成員一樣,而不必另外做任何聲明,這就是繼承帶來的代碼重用的優(yōu)點(diǎn)。
(3)另外還有一些操作,雖然對(duì)于各派生類而言都有意義,但是其語義并不相同。這時(shí),這些操作應(yīng)該聲明為基類的虛擬成員函數(shù)。各派生類雖然也默認(rèn)繼承了這些虛擬成員函數(shù)的聲明/實(shí)現(xiàn),但是語義上它們應(yīng)該對(duì)這些虛擬成員函數(shù)的實(shí)現(xiàn)進(jìn)行修改或者擴(kuò)展。另外在實(shí)現(xiàn)這些修改或擴(kuò)展過程中,需要用到額外的該派生類獨(dú)有的數(shù)據(jù)時(shí),將這些數(shù)據(jù)聲明為此派生類自己的數(shù)據(jù)成員。
再考慮更大背景下的繼承體系,當(dāng)更高層次的程序框架(繼承體系的使用者)使用此繼承體系時(shí),它處理的是一個(gè)抽象層次的對(duì)象集合(即基類)。雖然這個(gè)對(duì)象集合的成員實(shí)質(zhì)上可能是各種派生類對(duì)象,但在處理這個(gè)對(duì)象集合中的對(duì)象時(shí),它用的是抽象層次的操作。并不區(qū)分在這些操作中,哪些操作對(duì)各派生類來說是保持不變的,而哪些操作對(duì)各派生類來說有所不同。這是因?yàn)?,?dāng)運(yùn)行時(shí)實(shí)際執(zhí)行到各操作時(shí),運(yùn)行時(shí)系統(tǒng)能夠識(shí)別哪些操作需要用到“動(dòng)態(tài)綁定”,從而找到對(duì)應(yīng)此派生類的修改或擴(kuò)展的該操作版本。
也就是說,即只需關(guān)心它自己?jiǎn)栴}域的業(yè)務(wù)邏輯,只要保證正確,其任務(wù)就算完成了
。即使繼承體系內(nèi)部增加了某種派生類,或者刪除了某種派生類,或者某某派生類的某個(gè)虛擬函數(shù)的實(shí)現(xiàn)發(fā)生了改變,它的代碼不必任何修改。這也意味著,程序的模塊化程度得到了極大的提高。而模塊化的提高也就意味著可擴(kuò)展性、可維護(hù)性,以及代碼的可讀性的提高,這也是“面向?qū)ο蟆本幊痰囊粋€(gè)很大的優(yōu)點(diǎn)。

虛擬函數(shù)的靜態(tài)類型和動(dòng)態(tài)類型
先來看一個(gè)問題,如果一個(gè)子類重載的虛擬函數(shù)為privete,那么通過父類的指針可以訪問到它嗎?

#include <IOSTREAM> 
class B 
{ 
public: 
  virtual void fun()  
  { 
    std::cout << "base fun called"; 
  }; 
}; 
class D : public B  
{ 
private: 
  virtual void fun()  
  { 
    std::cout << "driver fun called"; 
  }; 
}; 
int main(int argc, char* argv[]) 
{   
  B* p = new D(); 
  p->fun(); 
  return 0; 
} 

運(yùn)行時(shí)會(huì)輸出

driver fun called

從這個(gè)實(shí)驗(yàn),可以更深入的了解虛擬函數(shù)編譯時(shí)的一些特征:

在編譯虛擬函數(shù)調(diào)用的時(shí)候,例如p->fun(); 只是按其靜態(tài)類型來處理的, 在這里p的類型就是B,不會(huì)考慮其實(shí)際指向的類型(動(dòng)態(tài)類型)。

也就是說,碰到p->fun();編譯器就當(dāng)作調(diào)用B的fun來進(jìn)行相應(yīng)的檢查和處理。

因?yàn)樵贐里fun是public的,所以這里在“訪問控制檢查”這一關(guān)就完全可以通過了。然后就會(huì)轉(zhuǎn)換成(*p->vptr[1])(p)這樣的方式處理, p實(shí)際指向的動(dòng)態(tài)類型是D,所以p作為參數(shù)傳給fun后(類的非靜態(tài)成員函數(shù)都會(huì)編譯加一個(gè)指針參數(shù),指向調(diào)用該函數(shù)的對(duì)象,我們平常用的this就是該指針的值), 實(shí)際運(yùn)行時(shí)p->vptr[1]則獲取到的是D::fun()的地址,也就調(diào)用了該函數(shù), 這也就是動(dòng)態(tài)運(yùn)行的機(jī)理。

為了進(jìn)一步的實(shí)驗(yàn),可以將B里的fun改為private的,D里的改為public的,則編譯就會(huì)出錯(cuò)。

C++的注意條款中有一條" 絕不重新定義繼承而來的缺省參數(shù)值" (Effective C++ Item37, never redefine a function's inherited default parameter value) 也是同樣的道理。
可以再做個(gè)實(shí)驗(yàn)

class B 
{ 
public: 
  virtual void fun(int i = 1)  
  { 
    std::cout << "base fun called, " << i; 
  }; 
}; 
class D : public B  
{ 
private: 
  virtual void fun(int i = 2)  
  { 
    std::cout << "driver fun called, " << i; 
  }; 
}; 

則運(yùn)行會(huì)輸出

driver fun called, 1

關(guān)于這一點(diǎn),Effective上講的很清楚“virtual 函數(shù)系動(dòng)態(tài)綁定, 而缺省參數(shù)卻是靜態(tài)綁定”,也就是說在編譯的時(shí)候已經(jīng)按照p的靜態(tài)類型處理其默認(rèn)參數(shù)了,轉(zhuǎn)換成了(*p->vptr[1])(p, 1)這樣的方式。

相關(guān)文章

  • C/C++程序設(shè)計(jì)的基本概念詳解

    C/C++程序設(shè)計(jì)的基本概念詳解

    這篇文章主要介紹了C++程序設(shè)計(jì)的基本概念詳解,文中有非常詳細(xì)的C語言使用教程及相關(guān)基礎(chǔ)知識(shí),對(duì)正在學(xué)習(xí)c語言的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-09-09
  • 詳解C++中的數(shù)據(jù)抽象

    詳解C++中的數(shù)據(jù)抽象

    這篇文章主要介紹了詳解C++中的數(shù)據(jù)抽象,數(shù)據(jù)抽象是指,只向外界提供關(guān)鍵信息,并隱藏其后臺(tái)的實(shí)現(xiàn)細(xì)節(jié),即只表現(xiàn)必要的信息而不呈現(xiàn)細(xì)節(jié),需要的朋友可以參考下
    2023-05-05
  • C++讀入

    C++讀入"N,X,Y,Z"格式文本文件到Eigen3 Matrix

    這篇文章主要介紹了C++讀入"N,X,Y,Z"格式文本文件到Eigen3 Matrix,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-04-04
  • C++特殊類設(shè)計(jì)概念與示例講解

    C++特殊類設(shè)計(jì)概念與示例講解

    本文介紹C++中三種特殊類設(shè)計(jì)模式:?jiǎn)卫J健⒐S模式和代理模式。通過詳細(xì)講解每種設(shè)計(jì)模式的實(shí)現(xiàn)原理和應(yīng)用場(chǎng)景,幫助讀者理解和掌握這些常用的面向?qū)ο笤O(shè)計(jì)模式,并提供示例代碼和技巧,便于實(shí)際應(yīng)用
    2023-04-04
  • C++詳細(xì)分析lambda表達(dá)式的本質(zhì)

    C++詳細(xì)分析lambda表達(dá)式的本質(zhì)

    Lambda表達(dá)式是現(xiàn)代C++在C ++ 11和更高版本中的一個(gè)新的語法糖 ,在C++11、C++14、C++17和C++20中Lambda表達(dá)的內(nèi)容還在不斷更新。 lambda表達(dá)式(也稱為lambda函數(shù))是在調(diào)用或作為函數(shù)參數(shù)傳遞的位置處定義匿名函數(shù)對(duì)象的便捷方法
    2022-06-06
  • C++11如何實(shí)現(xiàn)無鎖隊(duì)列

    C++11如何實(shí)現(xiàn)無鎖隊(duì)列

    這篇文章主要介紹了C++11如何實(shí)現(xiàn)無鎖隊(duì)列,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-08-08
  • C++的友元和內(nèi)部類你了解嗎

    C++的友元和內(nèi)部類你了解嗎

    這篇文章主要為大家介紹了C++的友元和內(nèi)部類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • c語言小游戲程序之彈跳小球的實(shí)現(xiàn)代碼

    c語言小游戲程序之彈跳小球的實(shí)現(xiàn)代碼

    這篇文章主要介紹了c語言小游戲程序之彈跳小球的實(shí)現(xiàn)代碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • C++使用MySQL-Connector/C++連接MySQL出現(xiàn)LNK2019錯(cuò)誤的解決方法

    C++使用MySQL-Connector/C++連接MySQL出現(xiàn)LNK2019錯(cuò)誤的解決方法

    這篇文章主要介紹了C++使用MySQL-Connector/C++連接MySQL出現(xiàn)LNK2019錯(cuò)誤的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • QT委托代理機(jī)制之Model?View?Delegate使用方法詳解

    QT委托代理機(jī)制之Model?View?Delegate使用方法詳解

    這篇文章主要介紹了QT委托代理機(jī)制之Model?View?Delegate的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評(píng)論