您好,登錄后才能下訂單哦!
這篇“C++不同繼承之間的關系是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“C++不同繼承之間的關系是什么”文章吧。
賦值兼容規則
C++面向對象編程中一條重要的規則是:公有繼承意味著 “是一個” 。一定要牢牢記住這條規則。在任何需要基類對象的地方都可以用公有派生類的對象來代替,這條規則稱賦值兼容規則。它包括
以下情況:
派生類的對象可以賦值給基類的對象,這時是把派生類對象中從對應基類中繼承來的隱藏對象賦值給基類對象。反過來不行,因為派生類的新成員無值可賦。
可以將一個派生類的對象的地址賦給其基類的指針變量,但只能通過這個指針訪問派生類中由基類繼承來的隱藏對象,不能訪問派生類中的新成員。同樣也不能反過來做。
派生類對象可以初始化基類的引用。引用是別名,但這個別名只能包含派生類對象中的由基類繼承來的隱藏對象。
如下代碼示例:
class Object { public: int value; public: Object(int x = 0) :value(x) {} ~Object() {} void print(int x) { value = x; cout << value << endl; } }; class Base : public Object { public: int num; public: Base(int x = 0):Object(x),num(x+10) {} }; int main() { Base base(10); Object obja(0); Object *op = &base; Object &ob = base; obja = base; return 0; }
class Person { int _id; public: Person(int id) :_id(id) { cout << "Create Person " << this << endl; } ~Person() { cout << "Destroy Person " << this << endl; } }; class Student : public Person { int _s_id; public: Student(int id, int s, int n) :_s_id(s), Person(id) { cout << "Create Student: " << this << endl; } ~Student() { cout << "Destroy Student" << this << endl; } }; int main() { Student stud(90010, 202201, 23); return 0; }
定義基類person,派生類student,當在主函數中創建一個派生類對象時,首先創建person對象,再創建student對象,析構時,先析構派生類對象,再析構基類對象
程序設計者在基類和派生類中都沒有定義拷貝構造函數;C++編譯器將自動產生按位拷貝的拷貝構造函數;在派生類的拷貝構造函數的初始化表中,加入基類拷貝構造函數的調用,是C++編譯器合成的代碼;
程序設計者在基類中定義拷貝構造函數;而在派生類中沒有定義拷貝構造函數;C++編譯器將會在派生類中自動產生按位拷貝的拷貝構造函數。并合成代碼,調用(關聯)基類的拷貝構造函數。
程序設計者在基類和派生類中都定義了拷貝構造函數;程序設計者在派生類中,沒有指定調用基類的拷貝構造函數時。C++編譯器合成的代碼調用基類的缺省構造函數,如果基類中沒有缺省構造函數。合成代碼失敗。
程序設計者在基類中沒有定義拷貝構造函數(C++編譯器將自動產生按位拷貝的拷貝構造函數)。而在派生類中定義了拷貝構造函數。程序設計者在派生類中,沒有指定調用基類的拷貝構造函數時。C++編譯器合成的代碼調用基類的缺省構造函數,如果基類中沒有缺省構造函數。
程序設計者在基類和派生類中都沒有重載operator=函數; C++編譯器將在基類和派生類中自動產生按位賦值的,重載operator=函數;C++編譯器會在派生類的重載賦值函數中,加入基類重載賦值函數的調用,是C++編譯器合成的代碼;(完成行為的統一);
程序設計者在基類中定義重載賦值函數;而在派生類中沒有定義重載賦值函數;C++編譯器將會在派生類中自動產生按位賦值的重載賦值函數。并合成代碼,調用(關聯)基類的重載賦值函數。
程序設計者在基類和派生類中都定義了重載賦值函數;程序設計者在派生類中,沒有指定調用基類的重載賦值函數時。C++編譯器不會合成調用基類的重載賦值函數的代碼。要在派生類的重載賦值函數調用基類的重載賦值函數,程序設計者必須自己加入調用代碼。
程序設計者在基類中沒有定義重載賦值函數(C++編譯器將自動產生按位賦值的重載賦值函數。而在派生類中定義了重載賦值函數。程序設計者在派生類中,沒有指定調用基類的重載賦值函數。C++編譯器不會合成調用基類的重載賦值函數的代碼。
使某個類的對象成為另一個類的數據成員,從而實現將一個類構筑在另一個類之上,這一過程稱為
"組合“,分層;
通過組合來體現 “有一個” 或 “用…來實現”。
例如,“汽車有一個發動機 或 汽車用發動機來實現 ” (has-a) 關系可以用單一組合表示為:
class Engine // 發動機 { private: int cylinderNum; // 氣缸數 public: Engine(int n = 4) :cylinderNum(n) {} void Start(); // 啟動 }; class Car { private: Engine eg; public: Car():eg(8) {} void StartCar(); };
**組合關系:**通過組合體現 “有一個” 或 “用…來實現”。組合是一種耦合度更強的關聯關系。存在組合關系的類表示“整體-部分”的關聯關系,“整體”負責“部分”的生命周期,他們之間是共生共死的;并且“部分”單獨存在時沒有任何意義。
同樣的“有一個”關系也能用私有繼承表示:
class Engine // 發動機 { private: int cylinderNum; // 氣缸數 public: Engine(int n = 4) :cylinderNum(n) {} void EnStart(); // 啟動 }; class Door { private: int doorNum; public: Door(int n = 5) :doorNum(n) {} } class Car : private Engine { public: Car() :Engine(8) {} void StartCar(); //通過發動引擎來發動這輛汽車 };
私有繼承: 要表示類之間 “用…來實現” 的關系,可以選擇是通過私有繼承實現。現在這種情況下,這一技術就比分層更有優勢,因為通過它可以讓你告訴別人:Engine使用起來不安全,它只能用來實現其它的類
**聚合關系:**通過聚合體現 “有一個” 或 “用…來實現”。 整體類與局部類之間松耦合,相互獨立。
class Engine // 發動機 { private: int cylinderNum; // 氣缸數 public: Engine(int n = 4) :cylinderNum(n) {} void Start(); // 啟動 }; class Car { private: Engine *peg; public: Car():peg(nullptr) {} void SetEngine(Engine *p) { peg = p;} void StartCar(); };
繼承與組合都是面向對象中代碼復用的方式。
公有繼承: 父類的內部細節對子類可見,其代碼屬于白盒式的復用;
例如: class Person ; class Student;
公有繼承的優缺點
優點:
支持擴展,通過繼承父類,可以設計較為復雜的系統,體現了由簡單到復雜的認識過程。
易于修改被復用的代碼。
缺點:
代碼白盒復用,父類的實現細節暴露給子類,破壞了封裝性。
當父類的實現代碼修改時,可能使得子類也不得不修改,增加維護難度。
子類缺乏獨立性,依賴于父類,耦合度較高。
不支持動態拓展,在編譯期就決定了父類。
**組合:**意味著 “用…來實現”; 對象之間的內部細節不可見,其代碼屬于黑盒式復用。
私有繼承意味著 “用…來實現”; 是組合關系,父類的內部細節對子類不可見,其代碼屬于黑盒式復用。
優點:
代碼黑盒復用,被包括的對象內部實現細節對外不可見,封裝性好。
整體類與局部類之間松耦合,相互獨立。
支持擴展每個類只專注于一項任務
支持動態擴展,可在運行時根據具體對象選擇不同類型的組合對象(擴展性比繼承好)。
缺點:
創建整體類對象時,需要創建所有局部類對象。導致系統對象很多。
在對象分析時明確具有是一個(is - a) 的關系,使用公有繼承。
在對象分析時明確具有 “有一個” 或 "用…來實現"關系,使用組合和私有繼承。
私有繼承和組合如何選擇?
答案很簡單:盡可能地使用組合,必須時才使用私有繼承。什么時候必須呢?這往往是指有保護成員
和/或虛函數介入的時候考慮考慮使用私有繼承。
//私有繼承在編碼過程中就要指定具體的父類,其關系在編譯期就確定,而組合的關系一般在運行時確定。
以上就是關于“C++不同繼承之間的關系是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。