在 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...