Thừakếnhiềumứcvàsựtrùngtên 4.1. Sơ đồ xây dựng các lớp dẫn xuất theo nhiềumức Như đã biết: + Khi đã định nghĩa một lớp (ví dụ lớp A), ta có thể dùng nó làm cơ sở để xây dựng lớp dẫn xuất (ví dụ B). + Đến lượt mình, B có thể dùng làm cơ sở để xây dựng lớp dẫn xuất mới (ví dụ C). + Tiếp đó lại có thể dùng C làm cơ sở để xây dựng lớp dẫn xuất mới. + Sự tiếp tục theo cách trên là không hạn chế. Sơ đồ trên chính là sựthừakếnhiều mức. Ngoài ra chúng ta cũng đã biết: + Một lớp có thể được dẫn xuất từ nhiều lớp cơ sở. + Một lớp có thể dùng làm cơ sở cho nhiều lớp. Hình vẽ dưới đây là một ví dụ về sơ đồ thừakế khá tổng quát, thể hiện được các điều nói trên: A B C D E F G H Diễn giải: Lớp D dẫn xuất từ A và B Lớp E dẫn xuất từ C Lớp F dẫn xuất từ D Lớp G dẫn xuất từ D và E Lớp H dẫn xuất từ E 4.2. Sựthừakếnhiều mức. + Như đã biết: Lớp dẫn xuất thừakế tất cả các thành phần (thuộc tính và phương thức) của lớp cở sở, kể cả các thành phần mà lớp cơ sở được thừa kế. + Hãy áp dụng nguyên lý trên để xét lớp G: - Lớp G thừakế các thành phần của các lớp D và E - Lớp D thừakế các thành phần của lớp A và B - Lớp E thừakế các thành phần của lớp C Như vậy các thành phần có thể sử trong lớp G gồm: - Các thành phần khai báo trong G (của riêng G) - Các thành phần khai báo trong các lớp D, E, A, B, C (được thừa kế). 255 256 4.3. Sựtrùngtên Như đã nói trong 4.2: Trong lớp G có thể sử dụng (trực tiép hay gián tiếp) các thành phần của riêng G và các thành phần mà nó được thừakế từ các lớp D, E, A, B, C. Yêu cầu về cách đặt tên ở đây là: + Tên các lớp không được trùng lặp + Tên các thành phần trong một lớp cũng không được trùng lặp + Tên các thành phần trong các lớp khác nhau có quyền được trùng lặp. Để phân biệt các thành phần trùngtên trong lớp dẫn xuất, cần sử dụng thêm tên lớp (xem ví dụ trong 4.4). 4.4. Sử dụng các thành phần trong lớp dẫn xuất Như đã nói ở trên: Thành phần của lớp dẫn xuất gồm: + Các thành phần khai báo trong lớp dẫn xuất + Các thành phần mà lớp dẫn xuất thừakế từ các lớp cơ sở Quy tắc sử dụng các thành phần trong lớp dẫn xuất: Cách 1: Dùng tên lớp vàtên thành phần. Khi đó Chương trình dịch C++ dễ dàng phân biệt thành phần thuộc lớp nào. Ví dụ: D h; // h là đối tượng của lớp D dẫn xuất từ A và B h.D::n là thuộc tính n khai báo trong D h.A::n là thuộc tính n thừakế từ A (khai báo trong A) h.D::nhap() là phương thức nhap() định nghĩa trong D h.A::nhap() là phương thức nhap() định nghĩa trong A Cách 2: Không dùng tên lớp, chỉ dùng tên thành phần. Khi đó Chương trình dịch C++ phải tự phán đoán để biết thành phần đó thuộc lớp nào. Cách phán đoán như sau: Trước tiên xem thành phần đang xét có trùngtên với một thành phần nào của lớp dẫn xuất không? Nếu trùng thì đó là thành phần của lớp dẫn xuất. Nếu không trùng thì tiếp tục xét các lớp cơ sở theo thứ tự: Các lớp có quan hệ gần với lớp dẫn xuất xét trước, các lớp quan hệ xa xét sau. Hãy chú ý trường hợp sau: Thành phần đang xét có mặt đồng thời trong 2 lớp cơ sở có cùng một đẳng cấp quan hệ với lớp dẫn xuất. Gặp trường hợp này Chương trình dịch C++ không thể quyết định được thành phần này thừakế từ lớp nào và buộc phải đưa ra một thông báo lỗi (xem ví dụ dưới đây). Cách khắc phục: Trường hợp này phải sử dụng thêm tên lớp như trình bầy trong cách 1. Ví dụ xét lớp dẫn xuất D. Lớp D có 2 cơ sở là các lớp A và B. Giả sử các lớp A, B và D được định nghĩa: class A { private: int n; float a[20]; public: void nhap(); void xuat(): 257 258 } ; class B { private: int m,n; float a[20][20]; public: void nhap(); void xuat(): } ; class D : public A, public B { private: int k; public: void nhap(); void xuat(): } ; Hãy chú ý các điểm sau: 1. Dùng các phương thức của các lớp A, B để xây dựng các phương thức của D // Xây dựng phương thức nhap() void D::nhap() { cout << “\n Nhap k : “ ; cin >> k ; // k là thuộc tính của D A::nhap(); // Nhập các thuộc tính mà D thừakế từ A B::nhap(); // Nhập các thuộc tính mà D thừakế từ B } // Xây dựng phương thức xuat() void D::xuat() { cout << “\n k = “ << k ; A::xuat(); // Xuất các thuộc tính mà D thừakế từ A B::xuat(); // Xuất các thuộc tính mà D thừakế từ B } 2. Làm việc với các đối tượng của lớp dẫn xuất D h ; // Khai báo h là đối tượng của lớp D h.nhap() ; // tương tương với h.D::nhap(); h.A::xuat(); // In giá trị các thuộc tính h.A::n và h.A::a h.B::xuat(); // In giá trị các thuộc tính h.B::m, h.B::n và h.B::a h.D::xuat() ; // In giá trị tất cả các thuộc tính của h h.xuat() ; // tương đương với h.D::xuat() ; 259 260 . Thừa kế nhiều mức và sự trùng tên 4.1. Sơ đồ xây dựng các lớp dẫn xuất theo nhiều mức Như đã biết: + Khi đã định nghĩa. và B Lớp E dẫn xuất từ C Lớp F dẫn xuất từ D Lớp G dẫn xuất từ D và E Lớp H dẫn xuất từ E 4.2. Sự thừa kế nhiều mức. + Như đã biết: Lớp dẫn xuất thừa kế