C 向上轉型

2021-10-03 21:14:52 字數 3545 閱讀 6607

在 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 型別的變數。資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如...