Constructor: tạo object ở trạng thái dùng được, không chỉ gọi new
Tiên quyết
Sau bài này bạn sẽ
- Phân biệt implicit constructor với khởi tạo theo contract riêng
- Đọc default và named arguments tại call site
- Kiểm field shadowing, width và storage riêng giữa các object
Object tồn tại chưa chắc đã đúng contract
Một frame có length và array payload. Nếu hai thành phần không khớp nhau, monitor có thể truy cập sai hoặc checker có thể bỏ sót byte. Constructor là nơi thiết lập invariant ban đầu; sau đó code vẫn phải bảo vệ invariant nếu các field được phép sửa.
Implicit constructor vẫn có khởi tạo theo type
Class Plain trong ví dụ không viết function new. Sau new, field bit 8 có giá trị 0 và string rỗng. Đó là hai type cụ thể đã kiểm trên flow này; không suy mọi numeric type đều khởi tạo 0, đặc biệt không dùng simulator 2-state để kết luận về mặc định X của type 4-state.
Function new không ghi return type
Frame định nghĩa function new(int length=2, bit[7:0] seed=8'h20). Nó gán length, cấp phát payload rồi điền các byte. Constructor không được biến thành một task chờ giao dịch; test kiểm toàn bộ construction xong ở time 0. Constructor chaining và typed constructors để dành bài inheritance, chưa có claim ở đây.
Call bỏ argument dùng default tại định nghĩa
defaults = new() dùng length 2 và seed 32. Hai byte lần lượt 32 và 33, tổng 65. Default có ý nghĩa API: đổi nó sẽ đổi các call bỏ argument. Đừng chỉ test một call truyền đủ tham số rồi cho rằng default đã được kiểm.
Named arguments làm rõ ý nghĩa nhưng không đổi type
named = new(.seed(8'hfe), .length(3)) đổi thứ tự tên trong call nhưng vẫn gắn đúng formal. Payload có ba byte 254/255/0 vì từng element 8 bit giữ giá trị modulo 256. Tổng 509 được tính từ các byte đã lưu, không phải tổng 254+255+256.
This phân biệt field với argument trùng tên
Constructor dùng this.length = length: bên trái là field, bên phải là formal. Nếu viết length = length, bạn có thể chỉ gán argument cho chính nó và field vẫn giữ giá trị khai báo 99. Đây là lỗi shadowing; không chữa bằng đổi expected length thành 99.
Kiểm cả size, nội dung và object độc lập
TB kiểm field length, payload.size và từng byte cho cả hai object. Sau đó đổi byte đầu của named thành 1 và xác nhận defaults vẫn 32. Việc mỗi constructor thực hiện new array tạo storage riêng trong example này; không suy mọi field kiểu handle đều tự deep-copy.
Hai call và một mutation sau construction
Expected tính trước chạy: Plain bit 0/string rỗng; defaults length 2/sum 65; named length 3/sum 509; sau sửa named thì defaults[0] vẫn 32; $time0. Có assert cho mỗi invariant thay vì chỉ in chuỗi PASS.
Tự kiểm tra
Đặt invariant cạnh constructor và test caller
Review constructor cùng các call dùng default/named arguments. Kiểm giá trị sau width conversion và array size, rồi sửa một object để phát hiện storage chia sẻ ngoài ý muốn. Không lấy new thành công làm bằng chứng dữ liệu đầu vào nào cũng hợp lệ; ví dụ chưa có API xử lý length âm hay quá lớn.
Nguồn và mức độ đối chiếu
- SystemVerilog Class Constructor — bản chụp resources.zip, Nguồn đào tạo đã đọc theo section. Trích dẫn; nguồn đã đọc các mục liên quan.
- Thí nghiệm nguyên bản ex.b5.constructor, 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, construction, static and const properties. 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.constructor, Source, self-checks, verification.json và mutation/capability probes. Trích dẫn; nguồn đã đọc toàn văn.
- SystemVerilog Class Constructor — bản chụp resources.zip, Explicitly Defining a Constructor; The Implicit Constructor. Trích dẫn; nguồn đã đọc các mục liên quan.
- this keywords in classes — bản chụp resources.zip, Example without this keyword; Example with this keyword; Example for this keyword with static method. Trích dẫn; nguồn đã đọc các mục liên quan.