C 向上轉型

2021-08-05 23:10:01 字數 2446 閱讀 2499

在 c/c++ 中經常會發生資料型別的轉換,例如將

int

型別的資料賦值給

float

型別的變數時,編譯器會先把

int

型別的資料轉換為

float

型別再賦值;反過來,

float

型別的資料在經過型別轉換後也可以賦值給

int

型別的變數。

資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如:

int a = 10.9;

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

輸出結果為 10,編譯器會將小數部分直接丟掉(不是四捨五入)。再如:

float b = 10;

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

輸出結果為 10.000000,編譯器會自動新增小數部分。

類其實也是一種資料型別,也可以發生資料型別轉換,

不過這種轉換只有在基類和派生類之間才有意義,並且只能將派生類賦值給基類,包括將派生類物件賦值給基類物件、將派生類指標賦值給基類指標、將派生類引用賦值給基類引用,這在 c++ 中稱為向上轉型(

upcasting

)。相應地,將基類賦值給派生類稱為向下轉型(

downcasting)。

向上轉型非常安全,可以由編譯器自動完成;向下轉型有風險,需要程式設計師手動干預。

21.將派生類物件賦值給基類物件

賦值的本質是將現有的資料寫入已分配好的記憶體中,物件的記憶體只包含了成員變數,所以物件之間的賦值是成員變數的賦值

,成員函式不存在賦值問題。執行結果也有力地證明了這一點,雖然有a=b;這樣的賦值過程,但是

a.display()

始終呼叫的都是

a 類的

display()

函式。換句話說,物件之間的賦值不會影響成員函式,也不會影響

this

指標。

將派生類物件賦值給基類物件時,會捨棄派生類新增的成員,也就是「大材小用」,如下圖所示:

可以發現,即使將派生類物件賦值給基類物件,基類物件也不會包含派生類的成員,所以依然不同通過基類物件來訪問派生類的成員。對於上面的例子,a.m_a 是正確的,但

a.m_b

就是錯誤的,因為

a 不包含成員

m_b。

這種轉換關係是不可逆的,只能用派生類物件給基類物件賦值,而不能用基類物件給派生類物件賦值。理由很簡單,基類不包含派生類的成員變數,無法對派生類的成員變數賦值。同理,同一基類的不同派生類物件之間也不能賦值。

要理解這個問題,還得從賦值的本質入手。賦值實際上是向記憶體填充資料,當資料較多時很好處理,捨棄即可;本例中將 b 賦值給

a 時(執行

a=b;

語句),成員

m_b

是多餘的,會被直接丟掉,所以不會發生賦值錯誤。但當資料較少時,問題就很棘手,編譯器不知道如何填充剩下的記憶體;如果本例中有

b= a;

這樣的語句,編譯器就不知道該如何給變數

m_b

賦值,所以會發生錯誤。

22.將派生類指標賦值給基類指標

除了可以將派生類物件賦值給基類物件(物件變數之間的賦值),還可以將派生類指標賦值給基類指標(物件指標之間的賦值)。我們先來看乙個多繼承的例子,繼承關係為:

我們將派生類指標 pd 賦值給了基類指標

pa,從執行結果可以看出,呼叫

display()

函式時雖然使用了派生類的成員變數,但是

display()

函式本身卻是基類的。也就是說,將派生類指標賦值給基類指標時,通過基類指標只能使用派生類的成員變數,但不能使用派生類的成員函式,這看起來有點不倫不類,究竟是為什麼呢?

pa 本來是基類

a 的指標,現在指向了派生類

d 的物件,這使得隱式指標

this

發生了變化,也指向了

d 類的物件,所以最終在

display()

內部使用的是

d 類物件的成員變數,相信這一點不難理解。

編譯器雖然通過指標的指向來訪問成員變數,但是卻不通過指標的指向來訪問成員函式:編譯器通過指標的型別來訪問成員函式。對於 pa,它的型別是

a,不管它指向哪個物件,使用的都是

a 類的成員函式。

概括起來說就是:編譯器通過指標來訪問成員變數,指標指向哪個物件就使用哪個物件的資料;編譯器通過指標的型別來訪問成員函式,指標屬於哪個類的型別就使用哪個類的函式。

本例中我們將最終派生類的指標 pd 分別賦值給了基類指標 pa、

pb、pc,按理說它們的值應該相等,都指向同一塊記憶體,但是執行結果卻有力地反駁了這種推論,只有 pa、

pb、pd 三個指標的值相等,

pc 的值比它們都大。也就是說,執行

pc = pd;

語句後,

pc 和

pd 的值並不相等。

C 向上轉型

在學習c 的過程中,一些基礎知識比如資料型別 控制結構 陣列等都與之前接觸的語言大同小異,還能夠理解,但是向上轉型這個概念還是第一次遇到。學習了一下後大致理解如下 向上轉型就是將子類轉型成父類,物件可以作為它本身的型別使用。先來看一段 public class animal public class...

C 向上轉型

類其實也是一種資料型別,也可以發生資料型別轉換,不過這種轉換只有在基類和派生類之間才有意義,並且只能將派生類賦值給基類,包括將派生類物件賦值給基類物件 將派生類指標賦值給基類指標 將派生類引用賦值給基類引用,這在 c 中稱為向上轉型 upcasting 相應地,將基類賦值給派生類稱為向下轉型 dow...

C 向上轉型

在 c 中經常會發生資料型別的轉換,例如將 int 型別的資料賦值給 float 型別的變數時,編譯器會先把 int 型別的資料轉換為 float 型別再賦值 反過來,float 型別的資料在經過型別轉換後也可以賦值給 int 型別的變數。資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如 i...