6.1.2 Định nghĩa một phân lớp đơn giản (2)

Nếu chúng ta muốn định nghĩa một lớp có tên là Y như là một phân lớp (hay còn gọi là lớp dẫn xuất, hoặc lớp con) của lớp cơ sở (còn gọi là lớp cha, hoặc superclass) có tên là X, chúng ta sử dụng cú pháp sau →

class Y : {visibility specifier} X {…};

Sự khác biệt so với ký hiệu chúng ta sử dụng trước đây là:

  • Đặt một dấu hai chấm sau tên của phân lớp
  • Có thể đặt một cái gọi là visibility specifier (cái này là optional, không nhất thiết phải có)
  • Thêm tên của lớp cơ sở (superclass)

Nếu có nhiều hơn một superclass, chúng ta phải nhập tất cả bằng cách sử dụng dấu phẩy làm dấu tách, như sau:

class A : X, Y, Z { … };

Hãy bắt đầu với trường hợp đơn giản nhất.

Chúng ta đã định nghĩa một lớp có tên Sub, là lớp con của lớp Super. Chúng ta cũng có thể nói rằng lớp Sub kế thừa từ lớp Super.

Lớp Sub không định nghĩa các biến mới cũng như các hàm mới. Điều này có nghĩa là bất kỳ đối tượng nào của lớp Sub sẽ kế thừa tất cả các đặc điểm của lớp Super. Vậy thực chất chúng các bản sao của các đối tượng của lớp Super ?

Không. Không phải vậy.

Nếu chúng ta biên dịch chương trình bên trên, chúng ta sẽ không có gì trừ các lỗi biên dịch nói rằng các phương thức putget không thể truy cập được. Tại sao ? WTF ? 🤔

Khi chúng ta bỏ qua visibility specifier, trình biên dịch giả định rằng chúng ta sẽ áp dụng “kế thừa riêng tư” (private inheritance). Điều này có nghĩa là tất cả các thành phần public của lớp cơ sở sẽ chuyển thành private, và các thành phần private của lớp cơ sở sẽ không thể truy cập được từ lớp dẫn xuất.

Chúng ta phải nói với trình biên dịch rằng chúng ta muốn giữ chính sách truy cập được sử dụng trước đó. Chúng ta thực hiện việc này bằng cách sử dụng “public” visibility specifier:

Đừng nhầm lẫn: điều này không có nghĩa là các thành phần private của lớp Super (ví dụ như biến storage) sẽ trở thành những public. Các thành phần private sẽ vẫn là private , các thành phần public sẽ vẫn public .

Đây chính xác là điều chúng ta muốn.