Bài giảng Lập trình hướng đối tượng - Chương 3: Thừa kế
Tại sao phải thừa kế ?
Các thuật ngữ
Thừa kế trong C++
Phạm vi truy cập trong các kiểu thừa kế
Đơn thừa kế và đa thừa kế
Sự tương hợp kiểu giữa lớp cơ sở và lớp dẫn xuất
Định nghĩa các hàm thành viên cho các lớp dẫn xuất
blic B D3: protected B D2: private B Not inherited Ví dụ: Truy cập các thành viên thừa kế class A { private: int m_iPrivate; protected: int m_iProtected; public: int m_iPublic; }; class B : public A {}; class C : protected A {}; class D : private A{}; void main() { A a; B b; C c; D d; a.m_iPrivate = 1; // error!!! a.m_iProtected = 1; // error!!! a.m_iPublic = 1; b.m_iPrivate = 1; // error!!! b.m_iProtected = 1; // error!!! b.m_iPublic = 1; c.m_iPrivate = 1; // error!!! c.m_iProtected = 1; // error!!! c.m_iPublic = 1; // error!!! d.m_iPrivate = 1; // error!!! d.m_iProtected = 1; // error!!! d.m_iPublic = 1; // error!!! } Ví dụ: Thừa kế public class Base { public: int m1; protected: int m2; private: int m3; }; class PublicClass : public Base { void test() { m1 = 1; // Still public m2 = 2; // Still protected m3 = 3; // Error. Not accessible } }; int main() { return 0; } Ví dụ: Thừa kế protected class Base { public: int m1; protected: int m2; private: int m3; }; class ProtectedClass : protected Base { void test() { m1 = 1; // Was public. Now protected m2 = 2; // Still protected m3 = 3; // Not accessible } }; int main() { return 0; } Ví dụ: Thừa kế private class Base { public: int m1; protected: int m2; private: int m3; }; class PrivateClass : private Base { void test() { m1 = 1; // Was public. Now private m2 = 2; // Was protected. Now private m3 = 3; // Not accessible } }; int main() { return 0; } Tóm tắt phạm vi truy cập Sự tương hợp kiểu Một minh họa của lớp dẫn xuất trong thừa kế public có thể sử dụng bất kỳ nơi đâu như là minh họa của lớp cơ sở Một minh họa của lớp dẫn xuất có thể không sử dụng được như là minh họa của lớp cơ sở nếu kiểu thừa kế là private hoặc protected Luôn luôn sử dụng thừa kế public trừ khi có một lý do chính đáng phải sử dụng các kiểu thừa kế khác Ví dụ: Tương hợp kiểu #ifndef BUILDING_H #define BUILDING_Hclass Building{ public: // Sets the number of rooms void setRooms(int numRooms); // Returns the number of rooms int getRooms(); // Sets the number of floors void setFloors(int numFloors); // Returns the number of floors int getFloors(); private: int rooms; // Number of rooms int floors; // Number of floors}; #endif Building Class - rooms: int - floors: int House Class - bedrooms: int - bathrooms: int Ví dụ: Tương hợp kiểu (tt) #ifndef HOUSE_H #define HOUSE_H #include "building.h"class House : public Building{ public: // Sets the number of bedrooms void setBedrooms(int numBedrooms); // Returns the number of bedrooms int getBedrooms(); // Sets the number of bathrooms void setBathrooms(int numBathrooms); // Returns the number of bathrooms int getBathrooms(); protected: int bedrooms; // Number of bedrooms int bathrooms; // Number of bathrooms};#endif #include using std::cout; using std::endl; #include "building.h“ #include "house.h“ void roomsPerFloor(const Building& aBuilding); int main() { House myHouse;// Calls House::setRooms() myHouse.setRooms(10); // Calls House::setFloors() myHouse.setFloors(2); // myHouse IS_A Building roomsPerFloor(myHouse); return 0; } Con trỏ và tương hợp kiểu Một con trỏ đến lớp cơ sở có thể trỏ đến một minh họa của một lớp dẫn xuất từ lớp cơ sở theo kiểu public Một tham chiếu đến lớp dẫn xuất kiểu public sẽ được chuyển đổi một cách tiềm ẩn thành một tham chiếu đến lớp cơ sở Ví dụ: Con trỏ và tham chiếu //Header file for Building class, building.h #ifndef BUILDING_H #define BUILDING_H #include using namespace std; class Building { private: int rooms; // Number of rooms int floors; // Number of floors public: // Display the number of rooms and floors void print() { cout using namespace std; class House: public Building { public: // Display the number of rooms and floors void print() { Building::print(); cout print(); // Calls Building::print()housePtr->print(); // Calls House::print()buildingPtr = housePtr; // Implicit conversionbuildingPtr->print(); // Calls Building::print() return 0; } Định nghĩa các hàm thành viên lớp dẫn xuất Một lớp dẫn xuất sẽ không thừa kế constructors, destructor hoặc toán tử gán từ lớp cơ sở Tuy nhiên, các constructors và toán tử gán của lớp dẫn xuất có thể gọi các constructors và toán tử gán của lớp cơ sở Định nghĩa các hàm thành viên lớp dẫn xuất (tt) Một đối tượng của một lớp dẫn xuất bao gồm 2 phần: một phần là đối tượng của lớp cơ sở của nó và một phần bổ sung của lớp dẫn xuất. Để tạo ra một đối tượng của lớp dẫn xuất, các đối tượng của lớp cơ sở phải được tạo ra. Định nghĩa các hàm thành viên lớp dẫn xuất (tt) Example: class B_class { // ... }; class D_class : public B_class{ // ... }; class DD_class : public D_class{ // ... }; DD_class dd; Định nghĩa các hàm thành viên lớp dẫn xuất (tt) Định nghĩa các hàm thành viên lớp dẫn xuất (tt) Trong một phân cấp thừa kế, các constructor được thực thi theo thứ tự: lớp cơ sở trước, lớp dẫn xuất sau Các đối tượng của lớp dẫn xuất được tạo ra theo thứ tự sau: lớp cơ sở trước, lớp dẫn xuất sau Các đối tượng lớp dẫn xuất được tạo theo các bước sau: Cấp phát vùng nhớ cho toàn bộ đối tượng (các thành viên lớp cơ sở và các thành viên lớp dẫn xuất) Gọi constructor lớp cơ sở để tạo phần thuộc về lớp cơ sở của đối tượng Khởi tạo các thành viên của lớp dẫn xuất bằng constructor của lớp dẫn xuất (thông qua danh sách khởi tạo) Thực thi phần thân của constructor lớp dẫn xuất Vấn đề ở bước 2: Contructor nào sẽ được gọi ? Example: class B_class { B_class(){ cout using namespace std; class A { public: int x1; }; class B : public A { public: float x2; }; class C : public A { public: double x3; }; class D : public B,public C { public: char x4; }; int main() { D obj; obj.x2=3.14159F; obj.x1=0; //Nhap nhang obj.x4='a'; obj.x3=1.5; cout using namespace std; class A { public: int x1; }; class B : virtual public A { public: float x2; }; class C : virtual public A { public: double x3; }; class D : public B,public C { public: char x4; }; int main() { D obj; obj.x2=3.14159F; obj.x1=0; //OK obj.x4='a'; obj.x3=1.5; cout 5 6 using std::cout; 7 using std::endl; 8 9 // class Base definition 10 class Base { 11 public: 12 virtual void print() const = 0; // pure virtual 13 14 }; // end class Base 15 16 // class DerivedOne definition 17 class DerivedOne : public Base { 18 public: 19 20 // override print function 21 void print() const { cout print(); 59 60 return 0; 61 62 } // end main c:\cpp4e\ch22\fig22_20_21\fig22_20.cpp(52) : error C2594: '=' : ambiguous conversions from 'class Multiple *' to 'class Base *' Error executing cl.exe. test.exe - 1 error(s), 0 warning(s) 1 2 // Using virtual base classes. 3 #include 4 5 using std::cout; 6 using std::endl; 7 8 // class Base definition 9 class Base { 10 public: 11 12 // implicit default constructor 13 14 virtual void print() const = 0; // pure virtual 15 16 }; // end Base class 17 18 // class DerivedOne definition 19 class DerivedOne : virtual public Base { 20 public: 21 22 // implicit default constructor calls 23 // Base default constructor 24 25 // override print function 26 void print() const { cout print(); 71 72 return 0; 73 74 } // end main DerivedTwo DerivedOne DerivedTwo Có nên sử dụng đa thừa kế không ? Multiple inheritance is a useful tool of many OO languages, but like any tool it should only be used where appropriate. If your solution can be simplified by using multiple inheritance, then by all means use it; but be cautious. A (solution) should be a simple as possible, but no simpler – A. Einstein Câu hỏi class Person { … … … public: Person(){ cout name,name); } } class Student : public Person { int id; public: Student (int id) { this->id=id; } } void main { Student st(3); cout id = id; cout salary = salary; cout hour = h; cout using namespace std; class Ancestor { public: int m_a; }; class Base1 : virtual public Ancestor { public: int m_b1; }; class Base2 : virtual public Ancestor { public: int m_b2; }; class Derived : public Base1, public Base2 { public: int m_d; }; int main(void) { Derived D; D.m_a = 10; // OK - No ambiguity cout class A{ int i1; protected: int i2; public: A(){ cout <<"Function A1"<< endl; i1=0; i2=1;} void seti(int inp){ cout <<"Function A2"<< endl; i1=inp; i2=0; } void f1(char *c){ cout <<"Function A3:"<< c << endl;} void print(){ cout <<"Ai1="<<i1<<" Ai2="<< i2 << endl;} ~A(){ cout <<"Function A4"<< endl;} }; class B:public A{ int i1; protected: int i3; public: B(){ cout <<"Function B1"<< endl; i1=0; i3=1; } void seti(int inp){ cout <<"Function B2"<< endl; i1=inp; i3=3; } void f1(int i){ cout <<"Function B3:"<< i << endl;} void print(){ A::print(); cout <<"Bi1="<<i1<<" Bi3="<< i3 << endl;} ~B(){ cout <<"Function B4"<< endl;} }; class C:private A{ int i1; public: C(){ cout <<"Function C1"<< endl; i1=0;} void print(){ A::print(); cout <<"Ci1="<<i1 << endl;} ~C(){ cout <<"Function C2"<< endl;} }; class D{ public: D(){ cout <<"Function D1"<< endl;} void f1(char *c){ cout <<"Function D2:"<< c << endl;} ~D(){ cout <<"Function D3"<< endl;} }; class E:public B,public D{ int i1; public: E(){ cout <<"Function E1"<< endl; i1=0;} ~E(){ cout <<"Function E2"<< endl;} }; Câu hỏi (tt) In main program (given below), 4 objects (a, b, c, e) are created. Explain, which data elements includes each of these objects. Some statements, in main program are incorrect. List them and explain the reason of errors. If the incorrect lines of main are discarded, what will be written on the screen when the C++ program below is compiled and run? void main() { A a; B b; C c; E e; a.i2=1; b.A::seti(3); a.seti(2); b.print(); b.f1("INPUT1"); c.A::seti(4); c.print(); c.f1("INPUT2"); e.seti(5); e.B::i3=7; e.print(); e.f1("INPUT3"); } Hỏi và Đáp
File đính kèm:
- Bài giảng Lập trình hướng đối tượng - Chương 3 Thừa kế.ppt