Hướng đối tượng - Đa thừa kế
Trang 1I Tính đa thừa kế
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ế.
Trang 2II Constructor và tính đa thừa kế.
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ừ đó.
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
Trang 3III Sự không rõ ràng trong tính đa thừa kế.
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 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
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
Trang 4IV Đa thừa kế với một cơ sở chung
một lần Hình ảnh sau đây cho thấy khả năng đó:
PERSON
TeachingAsitant
Mỗ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Ở ẢO
PERSON
Trang 5V Các lớp cơ sở ảo
class 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;}}
TEACHER STUDENT
TeachingAsitant
PERSON
Gây ra lỗi
Khắc phục: Sử dụng lớp cơ sở ảo
Trang 6VI Constructor và destructor
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
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
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
xuống.
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.
Trang 7VII Các biến trỏ đến các đối tượng
một lớ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ết
ptr -> show();
Trang 8Bài tập
Trang 9VIII Các hàm ảo và tính đa thể
tuỳ thuộc vào nó thuộc đối tượng nào.
Ví dụ:
…
public: void draw() {cout << “Draw Base\n”;}};
{ private: int radius;
public: circle(int r); void draw() {cout << “Draw circle”;}};
{ private: int length;
public: square(int l); void draw() {cout << “Draw square”;}};
void main()
{ circle c; square s;
ptr ->draw();
ptr->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 {
…
Đ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.