C++基類和派生類之間的轉換


本文講解內容的前提是派生類繼承基類的方式是公有繼承,關鍵字public

以下程序為講解用例。

 

 1 #include<iostream>
 2 using namespace std;
 3 
 4 class A
 5 {
 6 public:
 7     A(int m1, int n1):m(m1), n(n1){}
 8     void display();
 9 private:
10     int m;
11     int n;
12 };
13 
14 void A::display()
15 {
16     cout << "m = " << m << endl;
17     cout << "n = " << n << endl;
18 }
19 
20 class B :public A
21 {
22 public:
23     B(int m1, int n1, int p1) :A(m1, n1), p(p1){}
24     void display();
25 private:
26     int p;
27 };
28 
29 void B::display()
30 {
31     A::display();
32     cout << "p = " << p << endl;
33 }
34 
35 void print1(A& a)
36 {
37     a.display();
38 }
39 
40 void print2(B& b)
41 {
42     b.display();
43 }
44 
45 void print3(A a)
46 {
47     a.display();
48 }
49 
50 void print4(B b)
51 {
52     b.display();
53 }
54 
55 int main()
56 {
57     A a(3, 4);
58 //    a.display();
59     B b(10, 20, 30);
60 //    b.display();
61 
62     A * pa;
63     B * pb;
64     pa = &a;
65 //    pa->display();
66     pb = &b;
67 //    pb->display();
68 
69 //    pa = &b;
70 //    pa->display();
71 
72 //    pb = &a;              //錯誤。派生類指針不能指向基類對象。
73 
74 //    print1(b);
75 //    print2(a);            //錯誤。不能用基類對象給派生類引用賦值。
76 //    print3(b);
77 //    print4(a);            //錯誤。不能用基類對象給派生類對象賦值。
78 
79 //    pb = pa;              //不能用基類指針給派生類指針賦值。
80 
81     pb = (B*)pa;          //可以強制轉換,但是非常不安全。
82     pb->display();        //出現安全問題,p無法訪問,因為a中沒有p成員
83     system("pause");
84     return 0;
85 }

 

切記:派生類對象是基類對象,派生類中包含有基類的成員。基類對象不是派生類對象,它不能包含派生類型的成員。

 

/**************派生類到基類的轉化**************/

1。派生類對象地址賦值給基類指針

main函數中執行以下代碼

 1     A a(3, 4);
 2 //    a.display();
 3     B b(10, 20, 30);
 4 //    b.display();
 5 
 6     A * pa;
 7 //    B * pb;
 8 //    pa = &a;
 9 //    pa->display();
10 //    pb = &b;
11 //    pb->display();
12 
13     pa = &b;
14     pa->display();          //會輸出 10 20

pa為基類指針,指向派生類對象是合法的,因為派生類對象也是基類對象。語句會輸出派生類對象中基類部分。

注意:這里並不會調用派生類的display函數,調用的是基類的display函數,因為指針pa是基類指針,編譯器在編譯階段只知道pa的類型。如果要實現調用派生類的display函數,

需要用到虛函數實現多態性。之后的文章會講到。

進一步解釋一下編譯時和運行時的區別。

編譯時編譯器能知道pa的類型為A *,但是不知道它指向了哪個對象,假如有以下語句

1 A a(3, 4);
2 B b(10, 20, 30);
3 A* pa;
4 int number;
5 cin >> number;
6 if (number >= 0)
7     pa = &a;
8 else
9     pa = &b;

pa指向的對象類型依賴於輸入,運行時才輸入,所以編譯器是沒有辦法知道pa指向哪個類型的。

 

2.派生類對象賦值給基類引用

/**引用跟指針基本沒有區別,引用本質上是指針,是個指針常量,具體可以參照我的另一篇C++中的引用和指針的聯系和區別**/

main函數中執行以下代碼

1 A a(3, 4);
2 B b(10, 20, 30);
3 print1(b);           //會輸出 10 20

形參為基類引用,實參為派生類對象,派生類對象也是基類對象,可以賦值給基類引用。輸出派生類中基類部分。

注意:此時對象本身並未復制,b仍然是派生類對象,前面說過了引用就是一個指針。

 

3.派生類對象賦值給基類對象。

A a(3, 4);
B b(10, 20, 30);
print3(b);

派生類對象基類部分被復制給形參。

注意:實際上沒有從派生類對象到基類對象的直接轉換。對基類對象的賦值或初始化,實際上在調用函數,初始化時調用構造函數,賦值時調用賦值操作符。

 

/********************基類到派生類的轉化******************/

切記:這種轉換有可能引發嚴重的安全問題,編寫代碼時不要使用。沒有基類到派生類的自動轉換,原因在於基類對象只能是基類對象,不能包含派生類型的成員。

如果允許用基類對象給派生類對象賦值,那么就可以試圖使用該派生類對象訪問不存在的成員。

 

 1 A a(3, 4);
 2 B b(10, 20, 30);
 3 A * pa;
 4 B * pb;
 5 //    print2(a);            //錯誤。不能用基類對象給派生類引用賦值。
 6 //    print4(a);            //錯誤。不能用基類對象給派生類對象賦值。
 7 //    pb = &a;              //錯誤。派生類指針不能指向基類對象。
 8 
 9 pa = &a;
10 pb = &b;
11 
12 //pb = pa;                      //錯誤。不能用基類指針給派生類指針賦值。
13 
14 pb = (B*)pa;          //可以強制轉換,但是非常不安全。
15 pb->display();        //出現安全問題,p無法訪問,因為a中沒有p成員

注意到我們使用強制轉換時,當派生類添加了基類中不存在的成員時,會出現安全問題。

pb->display();會調用派生類的display函數,但是它指向的內存是基類對象a的內存,p不存在。會出現嚴重后果。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM