Inheritance và super: dùng lại hành vi mà vẫn thấy phần base
Tiên quyết
Sau bài này bạn sẽ
- Theo dõi constructor base và field mới của derived object
- Dùng super để cộng thêm hành vi thay vì lặp lại logic base
- Phân biệt nonvirtual call qua base handle với call qua derived handle
Derived object vẫn có phần dữ liệu base
Extended thêm extra vào phép tính của Base. Nó cần id đã được base constructor thiết lập; nếu tự viết lại công thức base ở nhiều nơi, thay đổi contract dễ làm hai phiên bản lệch nhau. Inheritance có ích khi đối tượng con thực sự dùng được qua API base.
Extends chia sẻ định nghĩa, không tạo hai object riêng
Extended kế thừa field id và thêm extra. base_view = child làm hai handle nhìn cùng object, không cắt dữ liệu extra ra khỏi object. Kiểu khai báo của handle vẫn quyết định member nào có thể gọi trực tiếp tại call site.
Super.new nhận đúng input cho phần base
Base constructor nhận id bắt buộc. Extended constructor gọi super.new(id) rồi gán extra. Main tạo 16 object với id 0..15 và extra=id+1, kiểm cả hai field sau construction; không chỉ kiểm tổng cuối vì hai lỗi có thể triệt tiêu nhau.
Super.total gọi phần triển khai của base một cách tường minh
Base.total trả 100+id. Extended.total trả super.total()+extra, nên với id 15/extra 16 kết quả 131. Cách này ghi rõ phần logic được dùng lại; super không phải một object độc lập để cập nhật field theo một lịch riêng.
Nonvirtual call còn phụ thuộc kiểu handle
Total trong ví dụ không virtual. Cùng một Extended object, child.total() dùng phần derived còn base_view.total() dùng Base.total. Đây là khác biệt được kiểm có chủ ý, không phải slicing dữ liệu. Bài virtual tiếp theo sẽ đổi chính sách dispatch.
Tính oracle độc lập theo chỉ số tạo object
Với n 0..15, base total 100+n, derived total 101+2 n. Tổng base là 1600+120=1720; tổng derived là 1616+240=1856. TB tính công thức trực tiếp theo n trước khi cộng output, không gọi DUT làm oracle của chính nó.
Truyền sai id lên base có thể làm mọi phép tính lệch
Mutation super.new(id+1) bị bắt với symptom inherit constructor or nonvirtual scope. Không chữa bằng đổi công thức expected theo id DUT trả về; input n mới là hợp đồng ban đầu. Tách kiểm field và method giúp thấy lỗi constructor sớm.
16 object và hai cách nhìn qua handle
Expected trước chạy: 16 object, base_sum1720, derived_sum1856, object cuối id 15/extra 16. Main không claim multiple inheritance, virtual dispatch hoặc dynamic casting; chúng không được suy từ pass của nonvirtual total.
Tự kiểm tra
Chọn reuse theo contract thay vì chỉ giảm dòng code
Đặt base invariant trong constructor và API base. Dùng super để mở rộng phần hành vi cần giữ; quyết định virtual riêng cho các extension point. Trong test, gọi qua đúng kiểu handle mà môi trường thật sẽ dùng.
Nguồn và mức độ đối chiếu
- SystemVerilog Inheritance — bản chụp resources.zip, Nguồn đào tạo đã đọc. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thí nghiệm nguyên bản ex.b5.inherit, Bằng chứng thực nghiệm. Trích dẫn; nguồn đã đọc toàn văn.
- IEEE 1800-2023 SystemVerilog LRM, Class handles, inheritance, virtual methods, access and parameterization. Chưa đối chiếu với văn bản nguồn (chưa mở).
- Thí nghiệm nguyên bản ex.b5.inherit, Source, self-checks, verification.json và mutation/capability probes. Trích dẫn; nguồn đã đọc toàn văn.
- SystemVerilog Inheritance — bản chụp resources.zip, A Basic Example; Accessing the Parent's Version With super. Trích dẫn; nguồn đã đọc các mục liên quan.