Inheritance và super: dùng lại hành vi mà vẫn thấy phần base

Khoảng 45 phútMức 1/3Bản nháp: một số khẳng định chưa đối chiếu spec

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.

[1]

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.

Inheritance và super: dùng lại hành vi mà vẫn thấy phần base

Expected tính trước chạy: INHERIT CHECK objects=16 base_sum=1720 derived_sum=1856 last_id=15 last_extra=16

tb.sv testbench
`timescale 1ns/1psclass Base;  int id;  function new(int id);this.id=id;endfunction  function int total();return 100+id;endfunctionendclassclass Extended extends Base;  int extra;  function new(int id,int extra);super.new(id);this.extra=extra;endfunction  function int total();return super.total()+extra;endfunctionendclassmodule tb_inherit;  Base base_view;  Extended child;  int base_sum=0,derived_sum=0;  initial begin    for(int n=0;n<16;n++)begin      child=new(n,n+1);base_view=child;      if(child.id!=n||child.extra!=n+1||base_view!=child||base_view.total()!=100+n||child.total()!=101+2*n)        $fatal(1,"inherit constructor or nonvirtual scope n=%0d",n);      base_sum+=base_view.total();derived_sum+=child.total();    end    if(base_sum!=1720||derived_sum!=1856)$fatal(1,"inherit sum");    $display("INHERIT CHECK objects=16 base_sum=1720 derived_sum=1856 last_id=15 last_extra=16");    $finish;  endendmodule

Đã kiểm chứng thế nào

  • Phân tích và elaborate theo LRM (pyslang 12.1.0)
  • Mô phỏng, exit 0 và output khớp kỳ vọng tính tay (Verilator 5.050, 2-state)

Output phải khớp: INHERIT CHECK objects=16 base_sum=1720 derived_sum=1856 last_id=15 last_extra=16

Verilator 2-state, không claim X/Z hoặc synthesis.

16 case nonvirtual method và super constructor; không claim virtual dispatch, multiple inheritance hoặc đầy đủ constructor-chain edge cases.

Các kiểm tra chạy lúc xây dựng nội dung (2026-11-06), không chạy trong trình duyệt. Kỳ vọng được tính tay trước khi chạy.

[2]

Tự kiểm tra

Tự kiểm tra: inherit

  1. Extended cuối có id 15 và extra 16. Child.total bằng bao nhiêu?
  2. Tổng base_view.total cho id 0..15 là bao nhiêu?
  3. Sau base_view=child, hai handle có nhìn cùng object không?
  4. Super.new(id) trong Extended dùng để làm gì?
  5. Cùng Extended object, vì sao base_view.total và child.total khác nhau?

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

  1. 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.
  2. 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.
  3. 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ở).
  4. 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.
  5. 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.