子類對象能夠看成父類對象使用(兼容性)ios
- 子類對象能夠直接賦值給父類對象
- 子類對象能夠直接初始化父類對象
- 父類指針能夠直接指向子類對象
- 父類引用能夠直接引用子類對象
#include <iostream> using namespace std; class Parent { public: int mi; void add(int i) { mi += i; } void add(int a, int b) { mi += (a + b); } }; class Child : public Parent { public: int mv; void add(int x, int y, int z) { mv += (x + y + z); } }; int main() { Parent p; Child c; p = c; // 子類對象賦值父類對象 Parent p1(c); // 子類對象初始化父類對象 Parent& rp = c; // 父類引用子類對象 Parent* pp = &c; // 父類指針指向子類對象 rp.mi = 100; rp.add(5); // 注意這裏! rp.add(10, 10); // pp->mv = 1000; // Error // pp->add(1, 10, 100); // Error return 0; }
編譯輸出: 無錯誤,無警告 分析 1: rp.add(5); rp.add(10, 10); 子類對象與父類對象中都定義了 add 函數,使用父類類型引用調用父類同名成員函數,爲何沒有發生同名覆蓋呢? 分析 2: pp->mv = 1000; pp->add(1, 10, 100); 子類對象中定義了成員變量 int mv; 與 void add(int x, int y, int z); 使用父類指針指向子類對象,進行調用爲何編譯器報錯呢? test.cpp: In function ‘int main()’: test.cpp:48: error: ‘class Parent’ has no member named ‘mv’ test.cpp:49: error: no matching function for call to ‘Parent::add(int, int, int)’ test.cpp:10: note: candidates are: void Parent::add(int) test.cpp:15: note: void Parent::add(int, int)
當使用父類指針( 引用 ) 指向子類對象時編程
- 子類對象退化爲父類對象
- 只能訪問父類中定義的成員
- 能夠直接訪問被子類覆蓋的同名成員
- 子類中能夠重定義父類中已經存在的成員函數
- 這種重定義發生在繼承中,叫作函數重寫【子類與父類成員函數的函數類型相同】
- 函數重寫是同名覆蓋的一種特殊狀況
class Parent { public: void print() { cout << "I'm Parent." << endl; } };
函數重寫 ==>安全
class Child : public Parent { public: void print() { cout << "I'm Child" << endl; } };
當函數重寫趕上賦值兼容會發生什麼?函數
#include <iostream> using namespace std; class Parent { public: void print() { cout << "I'm Parent." << endl; } }; class Child : public Parent { public: void print() { cout << "I'm Child." << endl; } }; void how_to_print(Parent* p) { p->print(); } int main() { Parent p; Child c; how_to_print(&p); // Expected to print: I'm Parent how_to_print(&c); // Expected to print: I'm Child return 0; }
輸出: I'm Parent. I'm Parent. 現象: how_to_print(&c); 爲何不是指望的輸出呢?這讓咱們在使用時產生困惑,甚至產生軟件錯誤!
問題分析spa
- 編譯期間,編譯器只能根據指針的類型判斷所指向的對象
- 根據賦值兼用, 編譯器認爲父類指針指向的是父類對象
- 所以,編譯結果只多是調用父類中的同名函數
void how_to_print(Parent* p) { p->print(); }
在編譯這個函數的時候,編譯器不可能知道指針 p 究竟指向了什麼。可是編譯器沒有理由報錯(語法正確)。因而,編譯器認爲最安全的作法是調用父類的 print 函數, 由於父類和子類確定都有相同的 print 函數。指針
編譯器的處理方法是合理的嗎? 是指望的嗎?code
合理,非指望!對象
(將在下一課中說明解決方法...)繼承
- 子類對象能夠看成父類對象使用(賦值兼容)
- 父類指針能夠正確的指向子類對象
- 父類引用能夠正確的表明子類對象
- 子類中能夠重寫父類中的成員函數
以上內容參考狄泰軟件學院系列課程,請你們保護原創!編譯器