Difficulty: Hard · Puzzle 3 of 6 · Topic: Virtual Method Puzzles
Predict what prints and explain why this is dangerous in constructor design.
class base;
function new();
init();
endfunction
virtual function void init();
$display("base init");
endfunction
endclass
class child extends base;
int cfg;
function new();
super.new();
cfg = 32'hCAFE;
endfunction
function void init();
$display("child cfg=%0h", cfg);
endfunction
endclass
initial begin
child c = new();
endConsider order: base constructor body runs before derived constructor body completes.
1) `super.new()` enters base constructor, which calls virtual `init()`.
2) Runtime object is `child`, so dynamic dispatch chooses `child::init()`.
3) `cfg` has not been assigned `32'hCAFE` yet, so print shows default value (typically 0).
4) Avoid virtual callbacks from constructors unless derived state is guaranteed initialized.Answer: It prints `child cfg=0` (or default), because virtual dispatch reaches child method before child constructor assigns `cfg`.
Checked by running the code in Verilator 5; the printed output supports the answer above. The shown code run in Verilator: the virtual call from the base constructor runs child::init before cfg is assigned.
Only `child::init` prints, never `base init`; by then the object is already a `child` but `cfg = 32'hCAFE` has not executed, so it shows 0. Virtual calls in constructors run derived code on partially initialized objects.
What safer pattern would you use in UVM: explicit `build()` hook or post-construction init API? Model answer: keep `new()` free of virtual calls and do the work in a phase (`build_phase`/`connect_phase`) or an explicit `init()` called after construction, when the whole derived object, its fields and its handles exist.
It prints child with cfg equal to 0, or the default value. The base constructor calls a virtual init, and the object is really a child, so dispatch goes to the child version before the child constructor has assigned cfg. The trap is believing the base constructor only sees base behavior. I would avoid virtual callbacks from constructors unless the derived state is guaranteed to be ready.