Kế thừa
Inheritance
Inheritance
Kế thừa / thừa kế (inhertance) là sự thừa hưởng tất cả các field, method, property của lớp con từ lớp cha.
Giống như con người thừa hưởng các đặc điểm về gen như tóc tai, màu da, chiều cao, ... từ bố mẹ. Class cũng được thừa hưởng các trường (field), phương thức (method), thuộc tính (property) của lớp cha, và cũng có thể mở rộng, thay thế chúng theo cách riêng.
Lớp con được thừa hưởng từ lớp cha gọi là subclass (lớp con) hoặc lớp dẫn xuất (derived class), còn lớp cha gọi là parentclass (lớp cha) hoặc lớp cơ sở (baseclass).
Chúng ta có hai lớp TParent và TChild như sau.
type
TParent = class
procedure Work;
end;
TChild = class(TParent)
procedure Learn;
end;
procedure TParent.Work;
begin
writeln('I am working');
end;
procedure TChild.Learn;
begin
writeln('I am learning');
end;
var
MySon: TChild;
begin
MySon := TChild.Create;
MySon.Work;
MySon.Free;
end.
Chú ý đến phương thức Work, rõ ràng nó không được khai báo ở lớp con, nhưng chúng ta có thể gọi nó trong thân chương trình ?
Đó là do kế thừa method Work của lớp cha. Vì thế chúng ta không cần khai báo lại mà vẫn có thể sử dụng, nó giúp tiết kiệm công sức khi viết code, cũng như tăng tính dễ dàng trong việc bảo trì mã.
Ở lớp con có thể ghi đè lại phương thức của lớp cha và thực hiện nó theo cách riêng. Ví dụ như code ở trên, chúng ta sẽ ghi đè (override) lại method TChild.Work (bị ẩn đi nhưng được thừa kế từ lớp cha) và thực hiện nó theo cách khác.
type
...
TChild = class(TParent);
...
procedure Work; override;
end;
...
procedure TChild.Work;
begin
writeln('Tre em chua den tuoi lam viec :D');
end;
Để lớp con có thể override (hoặc overload) method nào đó ở lớp cha thì ở lớp cha, method đó cần được đặt là virtual hoặc dynamic.
type
TCha = class
procedure Work; virtual;
end;
Xem thêm về override và overload ở bài Delphi OOP \ Override & Overload
Delphi cung cấp một cú pháp để một lớp con có thể gọi lại method ở lớp cha mà lớp con không có sẵn (do override lại rồi).
Ví dụ như đoạn code phía trên, mình sẽ ghi lại xuống đây.
type
TParent = class
procedure Work; virtual;
end;
TChild = class(TParent)
procedure Learn;
procedure Work; override;
end;
procedure TParent.Work;
begin
writeln('I am working');
end;
procedure TChild.Learn;
begin
writeln('I am learning');
end;
procedure TChild.Work;
begin
writeln('Tre em chua den tuoi lam viec :D');
end;
var
MySon: TChild;
begin
MySon := TChild.Create;
MySon.Work;
MySon.Free;
end.
Vậy, làm thế nào để gọi phương thức Work của lớp cha từ lớp con ? Không thể gọi MySon.Work vì ở lớp con method Work đã bị ghi đè khác rồi.
Để làm được điều đó, sử dụng từ khóa inherited.
Chúng ta sẽ chỉnh sửa lại method Work ở lớp con một chút.
procedure TChild.Work;
begin
writeln('Toi chua du tuoi de lam viec');
writeln('Nhung truoc do, cha toi da lam viec nhu the nay ...');
write(' ');
inherited Work;
end;
Dòng inherited Work; gọi đến method Work ở lớp cha. Method này không bị ghi đè.
Đến đây, chắc bạn đã hiểu cơ bản về từ khóa inherited này.
Bạn có thể sử dụng inherited; như một lệnh đơn. Những method nào nằm sau từ khóa này mặc định sẽ là của lớp cha. Ví dụ, thay vì viết (Các method Work, Eat, Sleep, ... là của lớp cha)
inherited Work;
inherited Eat;
inherited Sleep;
...
thì ta dùng từ khóa inherited một lần như sau
inherited;
Work;
Eat;
Sleep;
...
Dưới đây là một số mẹo với inherited mà bạn có thể sẽ cần trong tương lai:
Khi parent class không có method được inherited, thì delphi sẽ bỏ qua không gọi inherited method đó.
Inherited được đặt ở đầu tiên trong constructor và cuối cùng ở destructor (code bên dưới)
Sử dụng trong xử lý Windows Messages (nâng cao)
Code:
type
TClass = class(...)
public
constructor Create;
destructor Destroy;
end;
constructor TClass.Create;
begin
inherited Create; // Tạo cha trước rồi mới tạo con
...
end;
destructor TClass.Destroy;
begin
...
inherited Destroy; // Phá hủy con xong mới phá hủy cha
end;