Difficulty: Easy · Puzzle 5 of 6 · Topic: Virtual Method Puzzles
Predict output when non-virtual wrapper calls a virtual hook.
class base_seq;
function void run();
$display("base run pre");
body();
$display("base run post");
endfunction
virtual function void body();
$display("base body");
endfunction
endclass
class ext_seq extends base_seq;
function void body();
$display("ext body");
endfunction
endclass
initial begin
base_seq s;
ext_seq e;
e = new();
s = e;
s.run();
endAnalyze dispatch at each call site separately.
1) `run()` itself is non-virtual, so base wrapper always executes.
2) Inside wrapper, `body()` is virtual, so derived hook executes.
3) Output order: `base run pre`, `ext body`, `base run post`.Answer: Base wrapper runs, but virtual hook dispatches to derived body.
Checked by running the code in Verilator 5; the printed output supports the answer above. The shown code run in Verilator: the non-virtual wrapper calls the derived virtual hook.
The wrapper being non-virtual does not stop polymorphism inside it: `body()` is called on `this`, which is the `ext_seq` object, and `body` is virtual, so the derived hook runs.
Where is this pattern used in UVM phases and callbacks? Model answer: `uvm_sequence_base::start()` is itself a virtual task (so it is not a non-virtual wrapper), but it follows the same template shape: it sets up the sequencer and parent, then calls the virtual hooks `pre_start()`, `pre_body()`, `body()`, `post_body()` and `post_start()` in order, and you override the hooks (usually just `body()`). A cleaner non-virtual-wrapper example is the phasing machinery, which is not user-overridable and calls your virtual `run_phase`. The shared idea is a fixed outer sequence with overridable hooks. (From UVM 1.2 source and documentation; not run here.)
The base wrapper runs, and the virtual hook dispatches to the derived body. The wrapper run is non-virtual, so it always executes, and inside it the body call is virtual. The output order is base run pre, ext body, base run post. The trap is expecting the derived class to replace the wrapper, so I would check which method is virtual.