Tính thừa kế trong cơ sở dữ liệu
Chương 6 Tính kế thừa • Giới thiệu tính kế thừa • Điều khiển truy cập lớp cơ sở • Sử dụng các thành viên được bảo vệ • Hàm tạo, hàm hủy và tính kế thừa • Tính đa kế thừa • Lớp cơ sở ảo Chửụng 6 Tớnh keỏ thửứa 164 Chương 6 Tính kế thừa 165 I/ Giới thiệu tính kế thừa (inheritance) Tính kế thừa là cơ chế nhờ đó một lớp có thể kế thừa các đặc điểm của một lớp khác. Tính kế thừa hổ trợ khái niệm phân loại theo thứ bậc (hierachical classification) của lớp, ngoài ra còn hổ trợ tính đa hình (polymorphism). • Lớp cơ sở (base class) là lớp được kế thừa bởi một lớp khác. Lớp dẫn xuất (derive class) là lớp kế thừa từ một lớp cơ sở. Lớp cơ sở xác đònh các tính chất mà sẽ trở nên thông dụng cho các lớp dẫn xuất. Nghiã là lớp cơ sở hiển thò mô tả tổng quát nhất một tập hợp các đặc điểm. Một lớp dẫn xuất kế thừa các đặc điểm tổng quát này và bổ sung thêm các tính chất riêng của lớp dẫn xuất. Cú pháp khai báo cho lớp dẫn xuất class derived_class_name : access_specifier base_class_name { // body of class } ; base_class_name Tên lớp cơ sở derived_class_name Tên lớp dẫn xuất access_specifier chỉ đònh truy cập bao gồm : public, private và protected • Từ khoá public báo cho trình biên dòch biết rằng lớp cơ sở sẽ được kế thừa sao cho mọi thành viên chung của lớp cơ sở cũng sẽ là các thành viên chung của lớp dẫn xuất. Tuy nhiên, mọi thành viên riêng của lớp cơ sở vẫn còn riêng đối với nó và không được truy cập trực tiếp bởi lớp dẫn xuất. Ví dụ 1.1 // A simple example of inheritance. #include <iostream.h.h> B D Hình 6.1 Sự kế thừa đơn Chửụng 6 Tớnh keỏ thửứa 166 // Define base class. class base { int i; public: void set_i(int n); int get_i(); }; // Define derived class. class derived : public base { int j; public: void set_j(int n); int mul(); }; // Set value i in base. void base::set_i(int n) { i = n; } // Return value of i in base. int base::get_i() { return i; } // Set value of j in derived. void derived::set_j(int n) { j = n; } // Return value of base's i times derived's j. int derived::mul() { // derived class can call base class public member functions return j * get_i(); } Chương 6 Tính kế thừa 167 int main() { derived ob; ob.set_i(10); // load i in base ob.set_j(4); // load j in derived cout << ob.mul(); // displays 40 return 0; } • Một lớp cơ sở là không thuộc riêng về một lớp dẫn xuất. Lớp cơ sở có thể được kế thừa bởi nhiều lớp khác. Ví dụ 1.2 Lớp cơ sở chung Fruit có 2 lớp dẫn xuất Apple và Orange // An example of class inheritance. #include <iostream.h.h> #include <string.h> enum yn {no, yes}; enum color {red, yellow, green, orange}; void out(enum yn x); char *c[] = {"red", "yellow", "green", "orange"}; // Generic fruit class. class fruit { // in this base, all elements are public public: enum yn annual; enum yn perennial; enum yn tree; enum yn tropical; enum color clr; char name[40]; }; Chửụng 6 Tớnh keỏ thửứa 168 // Derive Apple class. class Apple : public fruit { enum yn cooking; enum yn crunchy; enum yn eating; public: void seta(char *n, enum color c, enum yn ck, enum yn crchy, enum yn e); void show(); }; // Derive orange class. class Orange : public fruit { enum yn juice; enum yn sour; enum yn eating; public: void seto(char *n, enum color c, enum yn j, enum yn sr, enum yn e); void show(); }; void Apple::seta(char *n, enum color c, enum yn ck, enum yn crchy, enum yn e) { strcpy(name, n); annual = no; perennial = yes; tree = yes; tropical = no; clr = c; cooking = ck; crunchy = crchy; eating = e; } void Orange::seto(char *n, enum color c, enum yn j, enum yn sr, enum yn e) { strcpy(name, n); Chửụng 6 Tớnh keỏ thửứa 169 annual = no; perennial = yes; tree = yes; tropical = yes; clr = c; juice = j; sour = sr; eating = e; } void Apple::show() { cout << name << " apple is: " << "\n"; cout << "Annual: "; out(annual); cout << "Perennial: "; out(perennial); cout << "Tree: "; out(tree); cout << "Tropical: "; out(tropical); cout << "Color: " << c[clr] << "\n"; cout << "Good for cooking: "; out(cooking); cout << "Crunchy: "; out(crunchy); cout << "Good for eating: "; out(eating); cout << "\n"; } void Orange::show() { cout << name << " orange is: " << "\n"; cout << "Annual: "; out(annual); cout << "Perennial: "; out(perennial); cout << "Tree: "; out(tree); cout << "Tropical: "; out(tropical); cout << "Color: " << c[clr] << "\n"; cout << "Good for juice: "; out(juice); cout << "Sour: "; out(sour); cout << "Good for eating: "; out(eating); cout << "\n"; } Chương 6 Tính kế thừa 170 void out(enum yn x) { if(x==no) cout << "no\n"; else cout << "yes\n"; } int main() { Apple a1, a2; Orange o1, o2; a1.seta("Red Delicious", red, no, yes, yes); a2.seta("Jonathan", red, yes, no, yes); o1.seto("Navel", orange, no, no, yes); o2.seto("Valencia", orange, yes, yes, no); a1.show(); a2.show(); o1.show(); o2.show(); return 0; } Bài tập I 1. Cho lớp cơ sở sau class area_cl { public: double height; double width; }; hãy tạo 2 lớp dẫn xuất box và isosceles kế thừa lớp area_cl. Với mỗi lớp hãy tạo hàm area() lần lượt trả về diện tích của một hộp hay một tam giác cân. Dùng các hàm tạo được tham số hoá để khởi đầu height và width. Chương 6 Tính kế thừa 171 II/ Điều khiển truy cập lớp cơ sở Chỉ đònh truy cập (access_specifier) xác đònh cách mà các phần tử của lớp cơ sở được kế thừa bởi lớp dẫn xuất. • Từ khoá private chỉ đònh các thành viên chung lớp cơ sở trở thành các thành viên riêng của lớp dẫn xuất, nhưng những thành viên này vẫn còn được truy cập bởi các hàm thành viên của lớp dẫn xuất. Ví dụ 2.1 #include <iostream.h> class base { int x; public: void setx(int n) { x = n; } void showx() { cout << x << '\n'; } }; // Inherit as public. class derived : public base { int y; public: void sety(int n) { y = n; } void showy() { cout << y << '\n'; } }; int main() { derived ob; ob.setx(10); // access member of base class ob.sety(20); // access member of derived class ob.showx(); // access member of base class ob.showy(); // access member of derived class Chương 6 Tính kế thừa 172 return 0; } Ví dụ 2.2 Lớp dẫn xuất không thể truy cập đến các thành viên riêng của lớp cơ sở class base { int x; public: void setx(int n) { x = n; } void showx() { cout << x << '\n'; } }; // Inherit as public - this has an error! class derived : public base { int y; public: void sety(int n) { y = n; } /* Cannot access private member of base class. x is a private member of base and not available within derived. */ void show_sum() { cout << x + y << '\n'; } // Error! void showy() { cout << y << '\n'; } }; Ví dụ 2.3 Lớp dẫn xuất kế thừa lớp cơ sở với chỉ đònh private // This program contains an error. #include <iostream.h> class base { int x; public: void setx(int n) { x = n; } void showx() { cout << x << '\n'; } }; [...]... một lớp cơ sở cho một lớp dẫn xuất khác, tạo ra thứ bậc lớp nhiều cấp. Khi đó cấp cơ sở gốc được gọi là lớp cơ sở giáng tiếp của lớp cơ sở thứ hai (Hình 6.2) . Hình 6.2 Kế thừa đa mức Hình 6.3 Kế thừa phân cấp (Multi level Inheritance) (Hierarchical Inheritance) Thứ hai , lớp dẫn xuất có thể kế thừa trực tiếp hơn một lớp cơ sở. Trường hợp này, hai hay nhiều lớp cơ sở được kết hợp... gián tiếp thông qua D1 hay tham chiếu về B được kế thừa gián tiếp thông qua D2 ? Để giải quyết tính không rõ ràng này, C++ có một cơ chế mà nhờ đó chỉ có một bản sao của B ở trong D3. Đặc điểm này được gọi là lớp cơ sở ảo . Có thể ngăn chặn được hai bản sao của lớp cơ sở cùng hiện diện trong đối tượng dẫn xuất bằng cách cho lớp cơ sở đó được kế thừa như virtual bởi bất kỳ các lớp dẫn xuất... Chương 6 Tính kế thừa 196 Khi nhiều lớp cơ sở được kế thừa trực tiếp bởi một lớp dẫn xuất, tồn tại một vấn đề : xuất hiện nhiều bản sao của lớp cơ sở cùng hiện diện trong đối tượng dẫn xuất. Chẳng hạn, xét hệ thống thứ bậc lớp sau Bời vì có hai bản sao của B trong D3, nên một tham chiếu đến một thành viên của B sẽ tham chiếu về B được kế thừa gián tiếp thông qua... Đa kế thừa Hình 6.5 Kế thừa lai (Multiple Inheritance) (Hybrid Inheritance) 2/ Tính chất • Khi một lớp cơ sở được dùng để dẫn ra một lớp mà lớp này lại được dùng làm lớp cơ sở cho một lớp dẫn xuất khác, thì các hàm tạo của các lớp được gọi theo thứ tự dẫn xuất . Cũng vậy, tất cả các hàm hủy được gọi theo thứ tự ngược lại . • Khi một lớp dẫn xuất kế thừa trực tiếp hơn một lớp cơ sở, ... << '\n'; return 0; } @ Nếu derived1 và derived2 không kế thừa base như một lớp ảo thì câu lệnh ob.i = 10; sẽ không rõ ràng và sẽ tạo ra lỗi thời gian biên dịch. • Khi một lớp cơ sở được kế thừa như một lớp ảo bởi một lớp dẫn xuất thì lớp cơ sở đó vẫn còn tồn tại trong lớp dẫn xuất . Chương 6 Tính kế thừa 179 void setab(int n, int m) { a = n; b = m; } }; ... class Chương 6 Tính kế thừa 184 • Trong hầu hết các trườnghợp, các hàm tạo đối với lớp cơ sở và lớp dẫn xuất sẽ không dùng đối số giống nhau . Nếu truyền một hay nhiều đối số cho mỗi lớp, cần phải truyền cho hàm tạo của lớp dẫn xuất tất cả các đối số mà cả hai lớp dẫn xuất và lớp cơ sở cần đến. Sau đó lớp dẫn xuất chỉ truyền cho lớp cơ sở những đối số nào mà lớp cơ sở cần đến. Ví... tập IV Chương 6 Tính kế thừa 180 Bài tập III 1. Lập bảng tổng kết về quyền truy cập của lớp dẫn xuất với sự kế thừa đơn Thuộc tính thành viên trong lớp cơ sở Chỉ định truy cập của lớp dẫn xuất Quyền truy cập của lớp dẫn xuất Public Public Private Protected ? ? ? Private Public Private Protected ? ? ? Protected Public Private Protected ? ? ? 2. Trong bài tập II/ 1.... bằng một lớp cơ sở tên là airship chứa thông tin về số lượng hành khách tối đa và trọng lượng hàng hoá tối đa (đơn vị tính là pound) mà máy bay có thể chở được. Chương 6 Tính kế thừa 205 Tạo hai lớp dẫn xuất airplane và balloons. Lớp airplane lưu kiểu của động cơ (gồm động cơ cánh quạt và động cơ phản lực), tầm xa (đơn vị tính là mile). Lớp balloon lưu thông tin về loại nhiên liệu sử dụng... D1 ↓ D2 B1 B2 D B D1 D2 D3 D4 B D1 D2 D Chương 6 Tính kế thừa 171 II/ Điều khiển truy cập lớp cơ sở Chỉ định truy cập ( access_specifier ) xác định cách mà các phần tử của lớp cơ sở được kế thừa bởi lớp dẫn xuất. • Từ khoá private chỉ định các thành viên chung lớp cơ sở trở thành các thành viên riêng của lớp dẫn xuất, nhưng những thành viên này vẫn... (gồm hai loại là hydrogen và helium), độ cao tối đa (đơn vị tính là feed). Viết chương trình minh hoạ hoạt động của chúng. Chương 6 Tính kế thừa 181 IV/ Hàm tạo, hàm hủy và tính kế thừa Lớp cơ sở, lớp dẫn xuất hoặc cả hai có thể có các hàm tạo và/hoặc hàm hủy. • Khi cả lớp cơ sở lẫn lớp dẫn xuất có các hàm tạo và hàm hủy, các hàm tạo . 165 I/ Giới thiệu tính kế thừa (inheritance) Tính kế thừa là cơ chế nhờ đó một lớp có thể kế thừa các đặc điểm của một lớp khác. Tính kế thừa hổ trợ khái. Tính kế thừa • Giới thiệu tính kế thừa • Điều khiển truy cập lớp cơ sở • Sử dụng các thành viên được bảo vệ • Hàm tạo, hàm hủy và tính kế