SystemVerilog Virtual Methods and Polymorphism

Polymorphism is what makes a UVM testbench reusable: a base transaction or driver handle can point to any derived object, and the virtual method dispatched is the one belonging to the actual object, not the handle type. This chapter shows the mechanism with runnable SystemVerilog.

Without virtual: the handle type wins

If a method is not virtual, the call resolves to the handle’s class. Mark it virtual and the call resolves to the object’s class — the behaviour you almost always want.

module tb;
  class Packet;
    virtual function string kind(); return "base"; endfunction   // virtual
    function string tag();        return "PKT";  endfunction      // non-virtual
  endclass
  class EthPacket extends Packet;
    function string kind(); return "ethernet"; endfunction        // override
    function string tag();  return "ETH";      endfunction
  endclass

  initial begin
    Packet p;               // base handle
    EthPacket e = new();
    p = e;                  // base handle points to derived object
    $display("virtual kind() -> %s   (dispatched by OBJECT)", p.kind());
    $display("non-virtual tag() -> %s (dispatched by HANDLE)", p.tag());
  end
endmodule
virtual kind() -> ethernet   (dispatched by OBJECT)
non-virtual tag() -> PKT (dispatched by HANDLE)

Read the log: kind() is virtual, so the base handle calls EthPacket‘s version (ethernet); tag() is not virtual, so it calls the base version (PKT) even though the object is an EthPacket. This is exactly why UVM marks its hooks (do_copy, do_compare, the phase methods) virtual.

Abstract base classes

Declare a class virtual class and a method pure virtual to force every subclass to implement it — a compile-time contract. This is how UVM’s uvm_sequence requires you to write a body().

▶ Try it in the ChipXpert Lab

Build a base Transaction with virtual compare() and two subclasses in the cocotb/SV verification lab, then drive a scoreboard through base-class handles to see polymorphism carry the right compare.

Open the Verification Lab →

Check yourself

Why must UVM callback and phase methods be declared <code>virtual</code>?

Because the framework holds your components and transactions through base-class handles (uvm_component, uvm_sequence_item). Only a virtual method dispatches to your derived override; a non-virtual one would call the empty base version, so your custom behaviour would never run.

What does <code>pure virtual</code> inside a <code>virtual class</code> enforce?

It declares a method with no body that every concrete subclass must implement, enforced at compile time. The abstract base cannot be instantiated directly — it defines an interface the subclasses must fulfil.

Have questions about this topic?
Share your question in comments or talk to our mentor team for batch guidance.

Learn Verilog with mentors, labs and placement support

This free series is maintained by the ChipXpert training team in Hyderabad & Bengaluru. Go deeper with instructor-led courses on real EDA tools.

Explore VLSI Courses
Next batch starts 18th November 2026
Start your VLSI career with ChipXpert

Live online and classroom batches in Hyderabad & Bengaluru. Fill in your details and a counsellor will call you back.

  • Real EDA tools in your browser: industry-standard EDAReal EDA tools in your browser
  • Recorded sessions on the elearn portalRecorded sessions
  • Placement assistance: resume, mock interviewsPlacement assistance
  • Merit scholarship up to 60% · EMI optionsScholarship up to 60%
Hi! Ask me about courses, fees, batches or discounts. ×
BENGALURU
HYDERABAD