類其實也是一種資料型別,也可以發生資料型別轉換,不過這種轉換只有在基類和派生類之間才有意義,並且只能將派生類賦值給基類,包括將派生類物件賦值給基類物件、將派生類指標賦值給基類指標、將派生類引用賦值給基類引用,這在 c++ 中稱為向上轉型(upcasting)。相應地,將基類賦值給派生類稱為向下轉型(downcasting)。
向上轉型非常安全,可以由編譯器自動完成;
向下轉型有風險,需要程式設計師手動干預(有時編譯器認為只是錯誤)
賦值的本質是將現有的資料寫入已分配好的記憶體中,物件的記憶體只包含了成員變數,所以物件之間的賦值是成員變數的賦值,成員函式不存在賦值問題。
將派生類物件賦值給基類物件時,會捨棄派生類新增的成員,所以不存在安全問題。
即使將派生類物件賦值給基類物件,基類物件也不會包含派生類的成員,所以依然不能通過基類物件來訪問派生類的成員。
這種轉換關係是不可逆的,只能用派生類物件給基類物件賦值,而不能用基類物件給派生類物件賦值。理由很簡單,
基類不包含派生類的成員變數,無法對派生類的成員變數賦值。同理,同一基類的不同派生類物件之間也不能賦值。
要理解這個問題,還得從賦值的本質入手。賦值實際上是向記憶體填充資料,當資料較多時很好處理,捨棄即可,所以不會發生賦值錯誤。但當資料較少時,問題就很棘手,編譯器不知道如何填充剩下的記憶體;如果本例中有b= a;這樣的語句,編譯器就不知道該如何給變數 m_b 賦值,所以會發生錯誤。
派生類指標賦值給基類指標
除了可以將派生類物件賦值給基類物件(物件變數之間的賦值),還可以將派生類指標賦值給基類指標(物件指標之間的賦值)
下面看一段示例**:
#include
using namespace std;
class a;
a::a(int a): m_a(a)
void a::display()
//中間派生類b
class b: public a;
b::b(int a, int b): a(a), m_b(b)
void b::display()
//基類c
class c;
c::c(int c): m_c(c)
void c::display()
//最終派生類d
class d: 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()
int main()
解 釋:
我們將派生類指標 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 c 中經常會發生資料型別的轉換,例如將 int 型別的資料賦值給 float 型別的變數時,編譯器會先把 int 型別的資料轉換為 float 型別再賦值 反過來,float 型別的資料在經過型別轉換後也可以賦值給 int 型別的變數。資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如...
C 向上轉型
在 c 中經常會發生資料型別的轉換,例如將 int 型別的資料賦值給 float 型別的變數時,編譯器會先把 int 型別的資料轉換為 float 型別再賦值 反過來,float 型別的資料在經過型別轉換後也可以賦值給 int 型別的變數。資料型別轉換的前提是,編譯器知道如何對資料進行取捨。例如 i...