在 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)。
向上轉型非常安全,可以由編譯器自動完成;向下轉型有風險,需要程式設計師手動干預。
下面的例子演示了如何將派生類物件賦值給基類物件:
#include
using namespace std;
//基類
classa;
a::a(
int a)
:m_a
(a)void a:
:display()
//派生類
classb:
public a;b:
:b(int a,
int b):a
(a),
m_b(b)
void b:
:display()
intmain()
執行結果:
class a
: m_a=
10class b
: m_a=
66, m_b=
99--
----
----
----
----
----
----
--class a
: m_a=
66class b
: m_a=
66, m_b=
99
本例中 a 是基類, b 是派生類,a、b 分別是它們的物件,由於派生類 b 包含了從基類 a 繼承來的成員,因此可以將派生類物件 b 賦值給基類物件 a。通過執行結果也可以發現,賦值後 a 所包含的成員變數的值已經發生了變化。
賦值的本質是將現有的資料寫入已分配好的記憶體中,物件的記憶體只包含了成員變數,所以物件之間的賦值是成員變數的賦值,成員函式不存在賦值問題。
將派生類物件賦值給基類物件時,會捨棄派生類新增的成員,也就是「大材小用」,如下圖所示:
可以發現,即使將派生類物件賦值給基類物件,基類物件也不會包含派生類的成員,所以依然不同通過基類物件來訪問派生類的成員。
這種轉換關係是不可逆的,只能用派生類物件給基類物件賦值,而不能用基類物件給派生類物件賦值。
除了可以將派生類物件賦值給基類物件(物件變數之間的賦值),還可以將派生類指標賦值給基類指標(物件指標之間的賦值)。我們先來看乙個多繼承的例子,繼承關係為:
下面的**實現了這種繼承關係:
#include
using namespace std;
//基類a
classa;
a::a(
int a)
:m_a
(a)void a:
:display()
//中間派生類b
classb:
public a;b:
:b(int a,
int b):a
(a),
m_b(b)
void b:
:display()
//基類c
classc;
c::c(
int c)
:m_c
(c)void c:
:display()
//最終派生類d
classd:
public b,
public c;d:
:d(int a,
int b,
int c,
int d):b
(a, b),c
(c),
m_d(d)
void d:
:display()
intmain()
執行結果:
class a
: m_a=
4class b
: m_a=
4, m_b=
40class c
: m_c=
400--
----
----
----
----
----
-pa=
0x9b17f8
pb=0x9b17f8
pc=0x9b1800
pd=0x9b17f8
本例中定義了多個物件指標,並嘗試將派生類指標賦值給基類指標。與物件變數之間的賦值不同的是,物件指標之間的賦值並沒有拷貝物件的成員,也沒有修改物件本身的資料,僅僅是改變了指標的指向。
引用在本質上是通過指標的方式實現的,既然基類的指標可以指向派生類的物件,那麼我們就有理由推斷:基類的引用也可以指向派生類的物件,並且它的表現和指標是類似的。
修改上例中 main() 函式內部的**,用引用取代指標:
int
main()
執行結果:
class a
: m_a=
4class b
: m_a=
4, m_b=
40class c
: m_c=
400
ra、rb、rc 是基類的引用,它們都引用了派生類物件 d,並呼叫了 display() 函式,從執行結果可以發現,雖然使用了派生類物件的成員變數,但是卻沒有使用派生類的成員函式,這和指標的表現是一樣的。
引用和指標的表現之所以如此類似,是因為引用和指標並沒有本質上的區別,引用僅僅是對指標進行了簡單封裝。
最後需要注意的是,向上轉型後通過基類的物件、指標、引用只能訪問從基類繼承過去的成員(包括成員變數和成員函式),不能訪問派生類新增的成員。
C 向上轉型
在學習c 的過程中,一些基礎知識比如資料型別 控制結構 陣列等都與之前接觸的語言大同小異,還能夠理解,但是向上轉型這個概念還是第一次遇到。學習了一下後大致理解如下 向上轉型就是將子類轉型成父類,物件可以作為它本身的型別使用。先來看一段 public class animal public class...
C 向上轉型
類其實也是一種資料型別,也可以發生資料型別轉換,不過這種轉換只有在基類和派生類之間才有意義,並且只能將派生類賦值給基類,包括將派生類物件賦值給基類物件 將派生類指標賦值給基類指標 將派生類引用賦值給基類引用,這在 c 中稱為向上轉型 upcasting 相應地,將基類賦值給派生類稱為向下轉型 dow...
C 向上轉型
在 c c 中經常會發生資料型別的轉換,例如將 int 型別的資料賦值給 float 型別的變數時,編譯器會先把 int 型別的資料轉換為 float 型別再賦值 反過來,float 型別的資料在經過型別轉換後也可以賦值給 int 型別的變數。資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如...