Lúc này chúng ta có trường Name
và phương thức Greet
của Coder
đã được kế thừa lại từ Person
, nhưng lại chỉ có thể hoạt động tốt nếu như object
được truyền vào ở vị trí tham số thứ hai là kiểu Person.Entity
; Còn nếu là kiểu Coder.Entity
thì trình biên dịch sẽ báo lỗi chứ không có sự chuyển đổi kiểu dữ liệu ngầm định được thực hiện.
Như vậy là chúng ta đang cần thêm khả năng định kiểu dữ liệu cho một biến có thể đại diện được cho bất kỳ kiểu object
nào trong cùng cây phả hệ hay hệ thống kế thừa. Và đây là một sự biểu thị của Tính Đa Hình Encapsulation
, hay chính xác hơn là Sub-typing Polymorphism
. Các kiểu Polymorphism
còn lại không thuộc về OOP
nói riêng thì chúng ta đã nói đến ở bài viết về Overloading Sub-program
và Generics
trong Sub-Series Procedural
trước đó.
Type'Class
Khi sử dụng thuộc tính Class
được gắn với các kiểu dữ liệu bằng cú pháp Type'Class
thì chúng ta sẽ nhận được một kiểu dữ liệu tổng hợp Union
biểu trưng cho tất cả các kiểu tagged
trong cùng mô hình cây kế thừa tính từ vị trí của chính kiểu Type
đó.
Ví dụ nếu chúng ta sử dụng Person.Entity'Class
để định kiểu cho một biến nào đó thì biến đó sẽ có thể nhận lưu một object
thuộc kiểu Person.Entity
hoặc tất cả các kiểu trong dòng kế thừa tính từ Person.Entity
trở đi.
Vậy nếu như chúng ta sửa lại định nghĩa của phương thức Greet
trong package Person
với tham số đứng sau sử dụng kiểu Person.Entity'Class
thì chúng ta sẽ có thể sử dụng một object Person.Entity
để Greet
một object Coder.Entity
mà không gặp phải thông báo lỗi.
package Person is type Entity is tagged; type Class is access all Entity'Class; -- ... procedure Greet (Self: in Entity; Other: in Entity'Class); end Person;
Ở đây chúng ta cũng đồng thời cập nhật định nghĩa của kiểu con trỏ Person.Class
thành access all Entity'Class
. Như vậy khi khởi tạo các object
mới, chúng ta có thể sử dụng một biến con trỏ kiểu này để lưu các object Coder.Entity
hoặc các kiểu khác trong cùng cây kế thừa nếu cần thiết.
Overriding Method
Nói về phương thức Greet
được định nghĩa tại Person
, tham số Other : in Entity'Class
lúc này đã có khả năng biểu thị cho nhiều kiểu object
khác nhau và như vậy chúng ta đã có thể nói rằng đây là một biểu hiện của Tính Đa Hình Polymorphism
. Tuy nhiên để biểu thị ở bề mặt kết quả hoạt động thì chúng ta có thể sẽ muốn cung cấp thêm một phiên bản định nghĩa mở rộng của Greet
trong Coder
.
with Person; use Person; package Person.Coder is -- ... procedure Greet (Self: in Entity; Other: in Person.Entity'Class); end Person.Coder;
Giả sử hành động Greet
ở đây, chúng ta sẽ chỉ cần sử dụng thêm duy nhất tên của người đối diện trong câu chào "Hi, " & Other.Name
. Nếu vậy kiểu object
mô phỏng người đối diện sẽ chỉ cần có ít nhất trường Name
đã được định nghĩa tại Person
và vì vậy nên để có logic hoạt động đầy đủ nhất chúng ta có thể định kiểu tham số Other
là Person.Entity'Class
.
with Ada.Text_IO; use Ada.Text_IO;
with Person; use Person; package body Person.Coder is procedure Greet ( Self : in Entity ; Other : in Person.Entity'Class ) is -- local begin Person.Entity (Self).Greet (Other); Put_Line ("A fellow Coder"); end Greet; end Person.Coder;
Để gọi tới định nghĩa của Greet
đã có sẵn trong Person
thì ở đây chúng ta cần chuyển kiểu của Self
thành Person.Entity
qua thao tác như trên. Và lúc này chúng ta đã có thể thử lại code tương tác tại main
, lần này chúng ta sẽ thử sử dụng kiểu con trỏ Person.Class
thay cho Coder.Class
của biến Me
để kiểm tra luôn hoạt động của kiểu con trỏ access all Person.Entity'Class
.
with Ada.Text_IO; use Ada.Text_IO;
with Person; use Person;
with Person.Coder; use Person.Coder; procedure Main is Me, Lucy : Person.Class;
begin Me := new Coder.Entity' ( Name => "Semi Dev_ " , Intellect => 0 ); Lucy := new Person.Entity' ( Name => "Lucy " ); Put_Line ("-- Message - - - -"); Me.Greet (Lucy.all); Put_Line ("-- Message - - - -"); Lucy.Greet (Me.all);
end Main;
alr run -- Message - - - -
Hi, Lucy
I'm Semi Dev_
A fellow Coder
-- Message - - - -
Hi, Semi Dev_
I'm Lucy