Difficulty: Medium · Puzzle 4 of 6 · Topic: Virtual Method Puzzles
A derived class adds a defaulted argument to a base method of the same name. Predict both prints, and say what changes if the base method were declared `virtual`.
class base_chk;
function int score(int e);
return e + 1;
endfunction
endclass
class ext_chk extends base_chk;
function int score(int e, int bonus = 10);
return e + bonus;
endfunction
endclass
initial begin
base_chk h;
ext_chk x;
x = new();
h = x;
$display("via base=%0d via ext=%0d", h.score(5), x.score(5));
endOnly a virtual base method lets the runtime object type pick the implementation. Without it, the handle type picks.
1) `base_chk::score` is non-virtual, so there is no override relationship; `ext_chk::score` is an unrelated method that hides the base name for `ext_chk` handles.
2) `h.score(5)` binds statically to `base_chk::score`: 5 + 1 = 6.
3) `x.score(5)` binds to `ext_chk::score(5, 10)`: 5 + 10 = 15.
4) If `base_chk::score` were `virtual`, the extra argument makes the derived prototype mismatch the virtual one. IEEE 1800 8.20 requires an exact match, so that is a compile error in a conforming tool (some tools are lenient), not silent hiding.Answer: Prints `via base=6 via ext=15`. The base method is non-virtual, so each call binds to its handle type. Making the base method virtual turns the same derived declaration into an illegal prototype mismatch.
Checked by running the code in Verilator 5; the printed output supports the answer above. The shown code run in Verilator: a non-virtual same-name method is hidden, not overridden.
Same name does not mean override. Whether the code is silently wrong (non-virtual: two different methods) or rejected (virtual: mismatched prototype) depends only on the base keyword; never rely on a tool's leniency to "just run the base version".
Would adding `virtual` on the derived method alone make `h.score(5)` print 15? Model answer: no. A `virtual` on the derived side only starts a new virtual method for `ext_chk` and below; `h` is a `base_chk` handle and `base_chk::score` stays non-virtual, so `h.score(5)` is still 6. Dispatch is decided by the base declaration the handle sees.
It prints via base equals 6 and via ext equals 15. The base method is non-virtual, so this is hiding, not overriding, and each call binds to its handle type. The base handle runs the one-argument version and the extended handle runs the two-argument version. The trap is that if the base method were virtual, the different prototype would be a compile error, so I would check the virtual keyword and the prototype.