Hướng đối tượng - Đa thừa kế
Sự kết nối độngI. Tính đa thừa kếI. Tính đa thừa kếĐa thừa kế là cách tạo một class mới Đa thừa kế là cách tạo một class mới từ nhiều class cơ sở.từ nhiều class cơ sở.#include <iostream.h>#include <conio.h>class base1 {public: void a(void); }class base2 {public: void b(void); }class derived: public base1,base2 {public: void c(void);} derived_object;Các quy tắc thừa kế và truy cập của cơ chế đa thừa kế cũng giống như tính đơn thừa kế. Sự kết nối độngII. Constructor và tính đa thừa kế.II. Constructor và tính đa thừa kế.Khi một đối tượng thuộc một lớp đa thừa kế được khởi tạo Khi một đối tượng thuộc một lớp đa thừa kế được khởi tạo nó sẽ lần lượt gọi đến các constructor của các lớp cha theo nó sẽ lần lượt gọi đến các constructor của các lớp cha theo thứ tự khai báo mà nó được thừa kế từ đó.thứ tự khai báo mà nó được thừa kế từ đó.Ví dụ: #include <iostream.h>#include <conio.h>class base1 {public: base1(void);};class base2 {public: base2(void);};class derived: public base1,base2 {public:derived(void);} derived_object;base1:: base1(void) {cout <<‘a’;}base2:: base2(void) {cout <<‘b’;}derived:: derived(void) {cout <<‘c’;}main() {getche(); return 0;}Kết quả trên màn hình sẽ là: abc. Sự kết nối độngIII. Sự không rõ ràng trong tính đa thừa kế.III. Sự không rõ ràng trong tính đa thừa kế.Nếu trong ít nhất hai trong các lớp cha có sự trùng lặp về Nếu trong ít nhất hai trong các lớp cha có sự trùng lặp về tên các dữ liệu hoặc hàm thì trình biên dịch sẽ không thể tên các dữ liệu hoặc hàm thì trình biên dịch sẽ không thể xác định được sẽ gọi đến thành viên nào! Do đó chính lập xác định được sẽ gọi đến thành viên nào! Do đó chính lập trình viên cần sử dụng toán tử phân giải hoạt vi để xác định trình viên cần sử dụng toán tử phân giải hoạt vi để xác định thành viên nào cần gọi. thành viên nào cần gọi. Biện pháp Ví dụ 28:Trường hợp gây ra lỗi:class Alpha {public: void display();};class Beta {public: void display();};class Gamma: public Alpha, public Beta {};Void main(){ Gamma::obj; obj.display;}Ambiguous, Alpha::display OR Beta::display Sự kết nối độngIV. Đa thừa kế với một cơ sở chungIV. Đa thừa kế với một cơ sở chungCó khả năng một class sẽ được dùng làm class cơ sở hơn Có khả năng một class sẽ được dùng làm class cơ sở hơn một lần. Hình ảnh sau đây cho thấy khả năng đó:một lần. Hình ảnh sau đây cho thấy khả năng đó:PERSONTEACHERSTUDENTTeachingAsitantMỗi lớp TEACHER và STUDENT đều chứa một bản sao của lớp PERSON. Do lớp TeachingAssistant được phái sinh từ các lớp TEACHER và STUDENT giờ đây lại chứa hai bản sao của lớp PERSON, gây ra rất nhiều sự mơ hồ cho trình biên dịch.BIỆN PHÁP: SỬ DỤNG LỚP CƠ SỞ ẢOPERSON Sự kết nối độngV. Các lớp cơ sở ảoV. Các lớp cơ sở ảoclass window{protected: int basedata;};class border: public window{};class menu: public window{};class border_and_menu: public border, public menu{public: int show() {return basedata;}}class window {protected: int basedata;};class border: virtual public window{};class menu: virtual public window{};class border_and_menu: public border, public menu{public: int show() {return basedata;}}TEACHERSTUDENTTeachingAsitantPERSONGây ra lỗi.Khắc phục: Sử dụng lớp cơ sở ảo Sự kết nối độngVI. Constructor và destructorVI. Constructor và destructorSự hiện diện của các lớp cơ sở ảo làm thay Sự hiện diện của các lớp cơ sở ảo làm thay đỏi thứ tự qua đó các constructor được đỏi thứ tự qua đó các constructor được gọi. Một lớp cơ sở ảo được gọi trước mọi gọi. Một lớp cơ sở ảo được gọi trước mọi lớp cơ sở không ảo. Nếu có nhiều lớp lớp cơ sở không ảo. Nếu có nhiều lớp không ảo, thứ tự được xác định bởi vị trí không ảo, thứ tự được xác định bởi vị trí của chúng trong đồ thị thừa kế từ trên của chúng trong đồ thị thừa kế từ trên xuống.xuống.Lệnh gọi các destructor cũng theo các quy Lệnh gọi các destructor cũng theo các quy tắc tương tự nhưng theo thứ tự ngược lại.tắc tương tự nhưng theo thứ tự ngược lại. Sự kết nối độngVII. Các biến trỏ đến các đối tượngVII. Các biến trỏ đến các đối tượngTa cTa cóó th thểể d dùngùng c cácác bi biếnến tr trỏỏ đểđể tr trỏỏ đếnđến mmộtột l lớpớp Ví dụ:Giả sử Base là một class.Base* ptr; // ptr là một biến trỏptr = new Base; // ptr trỏ đến một đối tượng thuộc lớp Base // Không thể dung toán tử dot (.) để tham chiếu đến các hàm thành viên// vì toán tử dot yêu cầu bên trái nó phải là một biến.// Nếu show() là một hàm thành viên của lớp Base thì cần phải viếtptr -> show(); Sự kết nối độngBài tậpBài tập Sự kết nối độngVIII. Các hàm ảo và tính đa thểVIII. Các hàm ảo và tính đa thểThuThuậtật ng ngữữ v virirtual tual ámám ch chỉỉ c cáiái g gìì đóđó g gây ra ây ra hihiệuệu ứngứng nh nhưưng khng khôông tng tồnồn t tạiại trong th trong thựcực t tạiại TTínhính đđa tha thểể (polym (polymororphism) phism) ámám ch chỉỉ đếnđến c cùngùng m mộtột h hàmàm nh nhưưng cng cóó th thểể c cóó nhi nhiềuều hànhhành vi khvi khácác nhau nhau tutuỳỳ thu thuộcộc v vàoào n nóó thu thuộcộc đốiđối t tượngượng n nàoào Ví dụ:class Shapes {…public: void draw() {cout << “Draw Base\n”;}};class circle: public Shapes{ private: int radius; public: circle(int r); void draw() {cout << “Draw circle”;}};class square: public Shapes{ private: int length; public: square(int l); void draw() {cout << “Draw square”;}};void main(){ circle c; square s; Shapes* ptr; ptr=&c; //gán địa chỉ của c cho ptrptr ->draw(); ptr=&s; //gán địa chỉ của s chp ptrptr->draw();}Vấn đề xảy ra là cả hai trường hợp đều cho kết xuất là Draw Base. Để khắc phục điều đó cần khai báo:class Shapes {…public: virtual void draw() {cout << “Draw Base\n”;}};Điều này sẽ làm cho các hàm thành viên trong các lớp con được thực thi. . Sự kết nối độngI. Tính đa thừa kếI. Tính đa thừa kế Đa thừa kế là cách tạo một class mới Đa thừa kế là cách tạo một class mới. tắc thừa kế và truy cập của cơ chế đa thừa kế cũng giống như tính đơn thừa kế. Sự kết nối độngII. Constructor và tính đa thừa kế. II. Constructor và tính đa