Cách dùng kế thừaCách 1: Để phản ánh mối quan hệ giữa các lớp Là công cụ để tổ chức và phân cấp lớp dựa vào sự chuyên biệt hóa, một vài hàm thành phần của lớp con là phiên bản hoàn
Trang 1KẾ THỪA - Inheritance
OOP
Trang 2TrianglePolygon
Trang 4Triangle
Polygon
class Polygon {
Trang 5x y r
x y z
Trang 7Kế thừa
Sự kế thừa là một đặc điểm của ngôn ngữ dùng
để biểu diễn mối quan hệ đặc biệt giữa các lớp
Các lớp được trừu tượng hóa và tổ chức thành một sơ đồ phân cấp lớp
Sự kế thừa là một mức cao hơn của trừu tượng hóa:
cung cấp một cơ chế gom chung các lớp có liên quan với nhau thành một mức khái quát hóa đặc trưng cho toàn bộ các lớp nói trên
www.themegallery.com
Trang 8Quan hệ “là 1”: Kế thừa được sử dụng thông
dụng nhất để biểu diễn quan hệ “là 1”
Một sinh viên là một người
Trang 9Lợi ích kế thừa
Tạo khả năng xây dựng lớp mới từ lớp đã có
Kế thừa có khả năng tạo cơ chế
khái quát hoá
chuyên biệt hoá.
từ một lớp đã có
Trong C++, kế thừa còn định nghĩa sự tương
thích, nhờ đó ta có cơ chế chuyển kiểu tự động
Kế thừa cho phép tổ chức các lớp chia sẻ mã
chương trình chung nhờ vậy có thể dễ dàng
sửa chữa, nâng cấp hệ thống
www.themegallery.com
Trang 10Cách dùng kế thừa
Cách 1: Để phản ánh mối quan hệ giữa các lớp
Là công cụ để tổ chức và phân cấp lớp dựa vào
sự chuyên biệt hóa,
một vài hàm thành phần của lớp con là phiên bản hoàn thiện hoặc đặc biệt hoá của phiên bản ở
lớp cha
Trong C++ mối quan hệ này thường được cài
đặt sử dụng:
• Kế thừa public.
Trang 11Cách dùng kế thừa
Cách 1: Để phản ánh sự chia sẻ mã chương
trình giữa các lớp
không có quan hệ về mặt ngữ nghĩa nhưng có
thể có tổ chức dữ liệu và mã chương trình tương
Trang 12Đặc tính Kế thừa
Thừa kế cho phép ta định nghĩa 1 lớp mới, gọi
là lớp con (subclass) hay lớp dẫn xuất (derived
(superclass) hay lớp cơ sở (base class)
Trang 13Đặc tính Kế thừa
Thừa kế cho phép nhiều lớp có thể dẫn xuất từ
1 lớp cơ sở
Thừa kế cũng cho phép một lớp có thể là dẫn
xuất của nhiều lớp cơ sở
Thừa kế không chỉ giới hạn ở 1 mức: Một lớp
dẫn xuất có thể là lớp cơ sở cho các lớp dẫn
xuất khác
www.themegallery.com
Trang 14Cú pháp khai báo kế thừa
Trang 15Cú pháp khai báo kế thừa
Cú pháp:
class DerivedClassName : access-level BaseClassName
access-level - kiểu truy cập
• private by default
• public
• private
Trang 17Kế thừa đơn – ví dụ
Xét hai khái niệm người và sinh viên với mối
quan hệ tự nhiên: một 'sinh viên' là một 'người'
Trong C++, ta có thể biểu diễn khái niệm trên, một sinh viên là một người có thêm một số
thông tin và một số thao tác (riêng biệt của sinh viên)
Ta tổ chức lớp sinh viên kế thừa từ lớp người
Lớp người được gọi là lớp cha (superclass) hay lớp cơ sở (base class)
Lớp sinh viên được gọi là lớp con (subclass) hay lớp dẫn xuất (derived class).
www.themegallery.com
Trang 18Kế thừa đơn – ví dụ
Trang 19~Nguoi() {delete [] HoTen;}
void An() const { cout<<HoTen<<" an 3 chen com";} void Ngu() const { cout<<HoTen<< " ngu ngay 8
tieng";}
void Xuat() const;
friend ostream& operator << (ostream &os, Nguoi& p);
};
Trang 20SinhVien(char *ht, char *ms, int ns) :
Nguoi(ht,ns) { MaSo = strdup(ms);
}
~SinhVien() {delete [] MaSo;}
void Xuat() const;
};
Trang 21 Về mặt dữ liệu: Mỗi đối tượng sinh viên tự động
có thành phần dữ liệu họ tên và năm sinh của người.
Về mặt thao tác: Lớp sinh viên được tự động kế thừa các thao tác của lớp cha
Riêng phương thức thiết lập không được kế thừa
www.themegallery.com
Trang 22Kế thừa đơn – ví dụ
Kế thừa public như trên hàm ý rằng một đối
tượng sinh viên là một đối tượng người
Nơi nào chờ đợi một đối tượng người có thể
đưa vào đó một đối tượng sinh viên (c/kiểu)
Trang 23Định nghĩa lại thao tác ở lớp con
Ta có thể định nghĩa lại các đặc tính ở lớp con
đã có ở lớp cha, việc định nghĩa chủ yếu là thao tác, bằng cách khai báo giống hệt như ở lớp
Trang 24Định nghĩa lại thao tác ở lớp con
Việc định nghĩa lại thao tác ở lớp con được thực hiện khi thao tác ở lớp con khác thao tác ở lớp cha Thông thường là các thao tác xuất, nhập
Ta cũng có thể định nghĩa lại thao tác ở lớp con trong trường hợp giải thuật ở lớp con đơn giản hơn (tô màu đa giác, tính diện tích )
Hoặc ở lớp con, thao tác không có tác dụng:
hàm quay 1 hình tròn(hình tròn kế thừa từ elip)
Trang 25Ràng buộc ngữ nghĩa ở lớp con
Kế thừa có thể được áp dụng cho quan hệ kếthừa mang ý nghĩa ràng buộc, đối tượng ở lớpcon là đối tượng ở lớp cha nhưng có dữ liệu bị
Trang 26Phạm vi truy xuất
lớp con có quyền truy xuất các thành phần
riêng tư của lớp cha hay không ? Vì chiều truy xuất là từ lớp con, cháu lên lớp cha nên ta gọi là truy xuất theo chiều dọc
của lớp cha, sau khi kế thừa xuống lớp con, thì thế giới bên ngoài có quyền truy xuất thông qua đối tượng của lớp con hay không ? Trong
Trang 27Phạm vi truy xuất
Thuộc tính public: Thành phần nào có thuộc tính public thì có thể được truy xuất từ bất cứ nơi nào (từ sau khai báo lớp).
Thuộc tính private: Thành phần nào có thuộc tính private thì nó là riêng tư của lớp đó Chỉ có các hàm thành phần của lớp và ngoại lệ là các hàm bạn được phép truy xuất, ngay cả các lớp con cũng không có quyền truy xuất.
Thuộc tính protected: cho phép qui định một vài thành phần nào đó của lớp là bảo mật, theo nghĩa thế giới bên ngoài không được phép truy xuất, nhưng tất cả các lớp con, cháu… đều được phép truy xuất
www.themegallery.com
Trang 29~SinhVien() {delete [] MaSo;}
// Nguoi::HoTen va Nguoi::NamSinh };
class NuSinh : public SinhVien {
Trang 30void Nguoi::Xuat() const {
cout << "Nguoi, ho ten: " << HoTen << " sinh " << NamSinh;
}
void SinhVien::Xuat() const {
cout << "Sinh vien, ma so: " << MaSo << ", ho ten:
" << HoTen; // Ok: co quyen truy xuat
// Nguoi::HoTen, Nguoi::NamSinh }
void SinhVien::Xuat() const {
Trang 31 các thành phần public của lớp cha trở thành
public của lớp con
Nói cách khác mọi thao tác của lớp cha được kế thừa xuống lớp con.
Vì vậy ta có thể sử dụng thao tác của lớp cha
cho đối tượng thuộc lớp con.
www.themegallery.com
Trang 32 Hầu hết các trường hợp kế thừa là kế thừa
public, nó cho phép tận dụng lại mã chương trình, đồng thời tạo khả năng thu gom các đặc điểm chung của các lớp vào một lớp cơ sở, nhờ
đó dễ dàng nâng cấp và sửa chữa (bảo trì).
Trang 33 Nói cách khác mọi thao tác của lớp cha đều bị
lớp con che dấu
Vì vậy trên quan điểm của thế giới bên ngoài lớp con không có các thao tác mà lớp cha có.
Sử dụng kế thừa private ta có thể chia sẻ mã
chương trình giữa các lớp có cấu trúc dữ liệu tương tự nhau nhưng vẫn giữ được tinh thần của từng lớp www.themegallery.com
Trang 34Kế thừa private – Ví dụ
Lớp List biểu diễn khái niệm danh sách liên kết
Lớp Stack biểu diễn ngăn xếp
Lớp Set biểu diễn khái niệm tập hợp
Nếu tổ chức Stack, Set như danh sách liên kết,
có thể dùng kế thừa private để tận dụng mã
chương trình chung
Trang 35typedef int Item;
typedef int bool;
const bool true = 1, false = 0;
class Link {
friend class List;
friend class ListIterator;
Link *next;
Item e;
Link(Item a, Link *p):e(a) {next = p;}
};
Trang 36void Insert(Item a); // add at head of list
void Append(Item a); // add at tail of list
head
void CleanUp();
bool Empty() const {return last == NULL;}
bool IsMember(Item x) const;
int Count() const;
Trang 37Item *ret = ce ? &((ce = ce->next)->e) : NULL;
if (ce == cs->last) ce = NULL;
return ret;
}
};
Trang 38class Stack:private List {
public:
Stack():List() {}
bool Empty() const {return List::Empty();}
bool Push(Item x) {Insert(x); return true;}
Trang 39bool IsMember(Item x) const {
return List::IsMember(x);
} int Count() const {return List::Count();}
void View() const {List::View();}
};
Trang 40Kế thừa private
Một số hàm thành phần của lớp cơ sở List có
thể cần thiết ở lớp con như hàm Empty trong
lớp Stack, hàm Empty, IsMember, Count trong lớp Set… Ta định nghĩa lại những hàm này
bằng cách gọi lại phiên bản trong lớp List
Một cách thay thế việc viết lại hàm như trên là khai báo lại các danh hiệu này trong phần public của lớp con
Trang 41};
Trang 42class Set:private List {
public:
Set():List(){}
void Add(Item x) {
if (!List::IsMember(x)) Insert(x);
} List::Empty(); // access specifier
List::IsMember;
List::Count;
List::View;
Trang 43Không dùng kế thừa private
Trang 44int Count() const {return l.Count();}
void View() const {l.View();}
Trang 45Kế thừa protected
Lớp con và friend có thể truy cập các thành viên
protected của lớp cơ sở
www.themegallery.com
Trang 47Access Control Over the Members
Two levels of access control over class members
Trang 48 The type of inheritance defines the minimum access level for the members of derived class that are inherited from the base class
With public inheritance, the derived class follow the same access permission as in the base class
With protected inheritance, only the public members inherited from
Access Rights of Derived Classes
private protected public private private private private protected private private protected public private protected public
Trang 49} daughter can access 3 of the 4 inherited members
Trang 50void set(int a, int b);
class son : protected mother{
void son :: foo ( ){
x = y = 20; // error, not a public member
set(5, 10);
cout<<“value of b ”<<b<<endl;
Trang 51What to inherit?
In principle, every member of a base class is inherited by a derived class
just with different access permission
However, there are exceptions for
constructor and destructor
operator=() member
friends
Since all these functions are class-specific
Trang 52Classes
The default constructor and the destructor
of the base class are always called when a new object of a derived class is created or destroyed.
public:
B (int a) {cout<<“B”<<endl;}
}
Trang 54The derived class can also define
its own members, in addition to
the members inherited from the
base class
Trang 55public:
void print () {cout<<“From B”<<endl;} }
Trang 56void set (int a, int b, double c) {
Point :: set(a, b); //same name function call
r = c;
} void print (); }
Access a Method
Circle C;
Trang 57Putting Them Together
Time is the base class
ExtTime is the derived class with public inheritance
The derived class can
inherit all members from the base class, except the
constructor
access all public and protected members of the base class
define its private data member
provide its own constructor
define its public member functions
override functions inherited from the base class
ExtTime
Time
Trang 58class Time Specification
class Time
{
public : void Set ( int h, int m, int s ) ; void Increment ( ) ;
void Write ( ) const ; Time ( int initH, int initM, int initS ) ; // constructor
Trang 59Time class
Trang 60Derived Class ExtTime
// SPECIFICATION FILE ( exttime.h)
#include “time.h”
enum ZoneType {EST, CST, MST, PST, EDT, CDT, MDT, PDT } ;
class ExtTime : public Time
// Time is the base class and use public inheritance
Trang 61Set Increment Write ExtTime ExtTime
Private data:
zone
Trang 62The default constructor of base
class, Time(), is automatically
ExtTime et1;
hrs = 0 mins = 0 secs = 0 zone = EST et1
Trang 63ExtTime *et2 =
new ExtTime(8,30,0,EST);
hrs = 8 mins = 30 secs = 0 zone = EST et2
5000
???
6000 5000
Trang 64Implementation of ExtTime
void ExtTime :: Set (int h, int m, int s, ZoneType
timeZone) {
Time :: Set (hours, minutes, seconds); // same name function call
zone = timeZone ; }
void ExtTime :: Write ( ) const // function overriding
{
string zoneString[8] =
{“EST”, “CST”, MST”, “PST”, “EDT”, “CDT”, “MDT”, “PDT”} ;
Trang 65thatTime.Write( ) ; // outputs 00:00:00 EST
thatTime.Set (16, 49, 23, CDT) ; thatTime.Write( ) ; // outputs 16:49:23 CDT
thisTime.Increment ( ) ; thisTime.Increment ( ) ; thisTime.Write ( ) ; // outputs 08:35:02 PST }
Trang 66Take Home Message
Inheritance is a mechanism for defining new
class types to be a specialization or an
augmentation of existing types
In principle, every member of a base class is
inherited by a derived class with different access permissions, except for the constructors
Trang 67Phương thức thiết lập và huỷ bỏ
Phương thức thiết lập và huỷ bỏ là các hàmthành phần đặc biệt dùng để tự động khởi độngđối tượng khi nó được tạo ra và tự động dọndẹp đối tượng khi nó bị hủy đi
Một đối tượng thuộc lớp con có chứa các thànhphần dữ liệu của các lớp cơ sở
Có thể xem lớp con có các thành phần ngầm định ứng với các lớp cơ sở.
Khi một đối tượng thuộc lớp con được tạo ra, các thành phần cơ sở cũng được tạo ra, nghĩa là phương thức thiết lập của các lớp cơ sở phải được gọi.
www.themegallery.com
Trang 68Phương thức thiết lập và huỷ bỏ
Trình biên dịch tự động gọi phương thức thiết
lập của các lớp cơ sở cho các đối tượng (cơ sở) nhúng vào đối tượng đạng được tạo ra
Đối với phương thức thiết lập của một lớp con, công việc đầu tiên là gọi phương thức thiết lập của các lớp cơ sở
Nếu mọi phương thức thiết lập của lớp cơ sở
đều đòi hỏi phải cung cấp tham số thì lớp con
bắt buộc phải có phương thức thiết lập để cung
Trang 70void Ve(int color) const;
void TinhTien(double dx, double dy) const;
};
HinhTron t(200,200,50); // Dung
Trang 71SinhVien(char *ht, char *ms, int ns) :
Nguoi(ht,ns) { MaSo = strdup(ms);
}
void Xuat() const;
};
Trang 72Khi một đối tượng bị huỷ đi, phương thức huỷ
bỏ của nó sẽ được gọi, sau đó phương thức
huỷ bỏ của các lớp cơ sở sẽ được gọi một cách
tự động Vì vậy lớp con không cần và cũng
không được thực hiện các thao tác dọn dẹp cho các thành phần thuộc lớp cha
Trang 73 Nhưng con trỏ đến đối tượng thuộc lớp con thì
không thể trỏ đến các đối tượng thuộc lớp cơ sở.
Có thể ép kiểu để con trỏ đến đối tượng thuộc lớp
con có thể trỏ đến đối tượng thuộc lớp cơ sở Tuy nhiên thao tác này có thể nguy hiểm.
Sử dụng ép kiểu đúng cách có thể giải quyết bài toán quản lý một danh sách các đối tượng khác kiểu.
www.themegallery.com
Trang 74Đa thừa kế
Đa thừa kế cho phép một lớp có thể là dẫn xuất của nhiều lớp cơ sở
class A: public B, public C {…};
Làm thế nào biểu thị tính độc lập của các thành phần cùng tên bên trong một lớp dẫn xuất?
Các phương thức thiết lập và hủy bỏ được gọi như thế nào: thứ tự, truyền thông tin, …?
Làm thế nào giải quyết tình trạng thừa kế xung
Trang 75Add your company slogan