Tính đa hình-các thành viên ảo của một lớp
Toán tử ảo Toán tử thực chất cũng là một hàm nên chúng ta có thể tạo ra các toán tử ảo trong một lớp. Tuy nhiên do đa năng hóa khi tạo một toán tử cần chú ý đến các kiểu của các toán hạng phải sử dụng kiểu của lớp cơ sở ...
Toán tử ảo
Toán tử thực chất cũng là một hàm nên chúng ta có thể tạo ra các toán tử ảo trong một lớp. Tuy nhiên do đa năng hóa khi tạo một toán tử cần chú ý đến các kiểu của các toán hạng phải sử dụng kiểu của lớp cơ sở gốc có toán tử ảo.
Ví dụ 6.4: Đa năng hóa toán tử với hàm toán tử là phương thức ảo.
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 6.4, kết quả ở hình 6.5

Hình 6.5: Kết quả của ví dụ 6.4
Có constructor và destructor ảo hay không?:
Khi một đối tượng thuộc lớp có phương thức ảo, để thực hiện cơ chế kết nối động, trình biên dịch sẽ tạo thêm một con trỏ vptr như một thành viên của lớp, con trỏ này có nhiệm vụ quản lý địa chỉ của phương thức ảo. Một lớp chỉ có một bảng phương thức ảo, trong khi đó có thể có nhiều đối tượng thuộc lớp, nên khi một đối tượng khác thuộc cùng lớp tạo ra thì con trỏ vptr đã còn tại. Chính vì vậy bảng phương thức ảo phải được tạo ra trước khi gọi thực hiện constructor, nên constructor không thể là phương thức ảo. Ngược lại do một lớp chỉ có một bảng phương thức ảo nên khi một đối tượng thuộc lớp bị hủy bỏ, bảng phương thức ảo vẫn còn đó, và con trỏ vptr vẫn còn đó. Hơn nữa, destructor được gọi thực hiện trước khi vùng nhớ dành cho đối tượng bị thu hồi, do đó destructor có thể là phương thức ảo. Tuy nhiên, constructor của một lớp có thể gọi phương thức ảo khác. Điều này hoàn toàn không có gì mâu thuẫn với cơ chế kết nối động.
Ví dụ 6.5:
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 6.5, kết quả ở hình 6.6

Hình 6.6: Kết quả của ví dụ 6.5
Nếu destructor không là phương thức ảo thì khi giải phóng đối tượng B chỉ có destructor của lớp cơ sơ được gọi mà thôi nhưng khi destructor là phương thức ảo thì khi giải phóng đối tượng B (ở dòng 25) destructor của lớp dẫn xuất được gọi thực hiện rồi đến destructor của lớp cơ sơ.
: Chúng ta sử dụng các phương thức ảo và tính đa hình để thực hiện bảng lương dựa trên loại người lao động. Chúng ta sử dụng lớp cơ sở Employ. Các lớp dẫn xuất của Employ là Boss mà người được trả tiền lương hàng tuần cố định bất chấp số giờ làm việc, CommissionWorker mà người có tiền lương cơ sở cộng thêm phần trăm của hàng bán, PieceWorker mà người được trả bởi số các mục sản xuất, và HourlyWorker mà người được trả bởi theo giờ và nhận ngoài giờ.
Ví dụ 6.6:
File EMPLOY.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File EMPLOY.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File BOSS.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File BOSS.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File COMMIS.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File COMMIS.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File HOURLY.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File HOURLY.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File PIECE.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File PIECE.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File CT6_6.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
Chúng ta chạy ví dụ 6.6, kết quả ở hình 6.7

Hình 6.7: Kết quả của ví dụ 6.6
Ví dụ 6.7: Viết lại chương trình ở ví dụ 5.6 với lớp cơ sở trừu tượng Shape.
File SHAPE.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File POINT.H
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |
File POINT.CPP
![]() |
||
![]() ![]() ![]() ![]() |
||
![]() ![]() |
||
![]() |