最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

C++將派生類賦值給基類(向上轉(zhuǎn)型)

2023-03-29 13:15 作者:c語言-小新  | 我要投稿

在 C/C++?中經(jīng)常會發(fā)生數(shù)據(jù)類型的轉(zhuǎn)換,例如將 int 類型的數(shù)據(jù)賦值給 float 類型的變量時,編譯器會先把 int 類型的數(shù)據(jù)轉(zhuǎn)換為 float 類型再賦值;反過來,float 類型的數(shù)據(jù)在經(jīng)過類型轉(zhuǎn)換后也可以賦值給 int 類型的變量。

數(shù)據(jù)類型轉(zhuǎn)換的前提是,編譯器知道如何對數(shù)據(jù)進(jìn)行取舍。例如:

  1. int a = 10.9;

  2. printf("%d\n", a);

輸出結(jié)果為 10,編譯器會將小數(shù)部分直接丟掉(不是四舍五入)。再如:
  1. float b = 10;

  2. printf("%f\n", b);

輸出結(jié)果為?10.000000,編譯器會自動添加小數(shù)部分。

類其實(shí)也是一種數(shù)據(jù)類型,也可以發(fā)生數(shù)據(jù)類型轉(zhuǎn)換,不過這種轉(zhuǎn)換只有在基類和派生類之間才有意義,并且只能將派生類賦值給基類,包括將派生類對象賦值給基類對象、將派生類指針賦值給基類指針、將派生類引用賦值給基類引用,這在 C++ 中稱為向上轉(zhuǎn)型(Upcasting)。相應(yīng)地,將基類賦值給派生類稱為向下轉(zhuǎn)型(Downcasting)。

向上轉(zhuǎn)型非常安全,可以由編譯器自動完成;向下轉(zhuǎn)型有風(fēng)險,需要程序員手動干預(yù)。本節(jié)只介紹向上轉(zhuǎn)型,向下轉(zhuǎn)型將在后續(xù)章節(jié)介紹。

向上轉(zhuǎn)型和向下轉(zhuǎn)型是面向?qū)ο缶幊痰囊环N通用概念,它們也存在于?Java、C#?等編程語言中。

將派生類對象賦值給基類對象

下面的例子演示了如何將派生類對象賦值給基類對象:


運(yùn)行結(jié)果:
Class A: m_a=10
Class B: m_a=66, m_b=99
----------------------------
Class A: m_a=66
Class B: m_a=66, m_b=99

本例中 A 是基類, B 是派生類,a、b 分別是它們的對象,由于派生類 B 包含了從基類 A 繼承來的成員,因此可以將派生類對象 b 賦值給基類對象 a。通過運(yùn)行結(jié)果也可以發(fā)現(xiàn),賦值后 a 所包含的成員變量的值已經(jīng)發(fā)生了變化。

賦值的本質(zhì)是將現(xiàn)有的數(shù)據(jù)寫入已分配好的內(nèi)存中,對象的內(nèi)存只包含了成員變量,所以對象之間的賦值是成員變量的賦值,成員函數(shù)不存在賦值問題。運(yùn)行結(jié)果也有力地證明了這一點(diǎn),雖然有a=b;這樣的賦值過程,但是 a.display() 始終調(diào)用的都是 A 類的 display() 函數(shù)。換句話說,對象之間的賦值不會影響成員函數(shù),也不會影響 this 指針。

將派生類對象賦值給基類對象時,會舍棄派生類新增的成員,也就是“大材小用”,如下圖所示:


可以發(fā)現(xiàn),即使將派生類對象賦值給基類對象,基類對象也不會包含派生類的成員,所以依然不同通過基類對象來訪問派生類的成員。對于上面的例子,a.m_a 是正確的,但 a.m_b 就是錯誤的,因?yàn)?a 不包含成員 m_b。

這種轉(zhuǎn)換關(guān)系是不可逆的,只能用派生類對象給基類對象賦值,而不能用基類對象給派生類對象賦值。理由很簡單,基類不包含派生類的成員變量,無法對派生類的成員變量賦值。同理,同一基類的不同派生類對象之間也不能賦值。

要理解這個問題,還得從賦值的本質(zhì)入手。賦值實(shí)際上是向內(nèi)存填充數(shù)據(jù),當(dāng)數(shù)據(jù)較多時很好處理,舍棄即可;本例中將 b 賦值給 a 時(執(zhí)行a=b;語句),成員 m_b 是多余的,會被直接丟掉,所以不會發(fā)生賦值錯誤。但當(dāng)數(shù)據(jù)較少時,問題就很棘手,編譯器不知道如何填充剩下的內(nèi)存;如果本例中有b= a;這樣的語句,編譯器就不知道該如何給變量 m_b 賦值,所以會發(fā)生錯誤。

將派生類指針賦值給基類指針

除了可以將派生類對象賦值給基類對象(對象變量之間的賦值),還可以將派生類指針賦值給基類指針(對象指針之間的賦值)。我們先來看一個多繼承的例子,繼承關(guān)系為:


下面的代碼實(shí)現(xiàn)了這種繼承關(guān)系:


運(yùn)行結(jié)果:
Class A: m_a=4
Class B: m_a=4, m_b=40
Class C: m_c=400
-----------------------
pa=0x9b17f8
pb=0x9b17f8
pc=0x9b1800
pd=0x9b17f8

本例中定義了多個對象指針,并嘗試將派生類指針賦值給基類指針。與對象變量之間的賦值不同的是,對象指針之間的賦值并沒有拷貝對象的成員,也沒有修改對象本身的數(shù)據(jù),僅僅是改變了指針的指向。

1) 通過基類指針訪問派生類的成員

請讀者先關(guān)注第 68 行代碼,我們將派生類指針 pd 賦值給了基類指針 pa,從運(yùn)行結(jié)果可以看出,調(diào)用 display() 函數(shù)時雖然使用了派生類的成員變量,但是 display() 函數(shù)本身卻是基類的。也就是說,將派生類指針賦值給基類指針時,通過基類指針只能使用派生類的成員變量,但不能使用派生類的成員函數(shù),這看起來有點(diǎn)不倫不類,究竟是為什么呢?第 71、74 行代碼也是類似的情況。

pa 本來是基類 A 的指針,現(xiàn)在指向了派生類 D 的對象,這使得隱式指針 this 發(fā)生了變化,也指向了 D 類的對象,所以最終在 display() 內(nèi)部使用的是 D 類對象的成員變量,相信這一點(diǎn)不難理解。

編譯器雖然通過指針的指向來訪問成員變量,但是卻不通過指針的指向來訪問成員函數(shù):編譯器通過指針的類型來訪問成員函數(shù)。對于 pa,它的類型是 A,不管它指向哪個對象,使用的都是 A 類的成員函數(shù),具體原因已在《C++函數(shù)編譯原理和成員函數(shù)的實(shí)現(xiàn)》中做了詳細(xì)講解。

概括起來說就是:編譯器通過指針來訪問成員變量,指針指向哪個對象就使用哪個對象的數(shù)據(jù);編譯器通過指針的類型來訪問成員函數(shù),指針屬于哪個類的類型就使用哪個類的函數(shù)。

2) 賦值后值不一致的情況

本例中我們將最終派生類的指針 pd 分別賦值給了基類指針 pa、pb、pc,按理說它們的值應(yīng)該相等,都指向同一塊內(nèi)存,但是運(yùn)行結(jié)果卻有力地反駁了這種推論,只有 pa、pb、pd 三個指針的值相等,pc 的值比它們都大。也就是說,執(zhí)行pc = pd;語句后,pc 和 pd 的值并不相等。

這非常出乎我們的意料,按照我們通常的理解,賦值就是將一個變量的值交給另外一個變量,不會出現(xiàn)不相等的情況,究竟是什么導(dǎo)致了 pc 和 pd 不相等呢?我們將在《將派生類指針賦值給基類指針時到底發(fā)生了什么?》一節(jié)中解開謎底。

將派生類引用賦值給基類引用

引用在本質(zhì)上是通過指針的方式實(shí)現(xiàn)的,這一點(diǎn)已在《引用在本質(zhì)上是什么,它和指針到底有什么區(qū)別》中進(jìn)行了講解,既然基類的指針可以指向派生類的對象,那么我們就有理由推斷:基類的引用也可以指向派生類的對象,并且它的表現(xiàn)和指針是類似的。

修改上例中 main() 函數(shù)內(nèi)部的代碼,用引用取代指針:

  1. int main(){

  2. D d(4, 40, 400, 4000);


  3. A &ra = d;

  4. B &rb = d;

  5. C &rc = d;


  6. ra.display();

  7. rb.display();

  8. rc.display();


  9. return 0;

  10. }

運(yùn)行結(jié)果:
Class A: m_a=4
Class B: m_a=4, m_b=40
Class C: m_c=400

ra、rb、rc 是基類的引用,它們都引用了派生類對象 d,并調(diào)用了 display() 函數(shù),從運(yùn)行結(jié)果可以發(fā)現(xiàn),雖然使用了派生類對象的成員變量,但是卻沒有使用派生類的成員函數(shù),這和指針的表現(xiàn)是一樣的。

引用和指針的表現(xiàn)之所以如此類似,是因?yàn)橐煤椭羔槻]有本質(zhì)上的區(qū)別,引用僅僅是對指針進(jìn)行了簡單封裝,讀者可以猛擊《引用在本質(zhì)上是什么,它和指針到底有什么區(qū)別》一文深入了解。

最后需要注意的是,向上轉(zhuǎn)型后通過基類的對象、指針、引用只能訪問從基類繼承過去的成員(包括成員變量和成員函數(shù)),不能訪問派生類新增的成員。


C++將派生類賦值給基類(向上轉(zhuǎn)型)的評論 (共 條)

分享到微博請遵守國家法律
高州市| 房产| 阿拉善左旗| 泾源县| 岳普湖县| 固原市| 革吉县| 新宾| 封丘县| 安泽县| 景德镇市| 江口县| 松潘县| 永德县| 隆子县| 高清| 连城县| 磐安县| 兴业县| 辰溪县| 安泽县| 枝江市| 肇源县| 同江市| 江源县| 东城区| 泸水县| 克什克腾旗| 昭平县| 青浦区| 鸡西市| 榕江县| 鄯善县| 翼城县| 瑞安市| 高邑县| 怀集县| 万源市| 克山县| 临高县| 庆阳市|