Polymorphism in SystemVerilog: Virtual Methods, Casting and Why UVM Needs It

Polymorphism in SystemVerilog lets a handle of a base class type point to an object of a derived class, so that calling a virtual method runs the derived class’s version. It is the mechanism that makes UVM testbenches reusable: a driver written for a base transaction type works, unchanged, with any derived transaction, and the factory can swap in a derived component without editing the environment.

The three ingredients

  1. Inheritance. A derived class extends a base class: class my_tx extends base_tx;
  2. Base-class handles. A variable declared as base_tx can hold a my_tx object, because a derived object is-a base object.
  3. Virtual methods. A method declared virtual in the base class is dispatched at run time according to the object’s actual class, not the handle’s declared type.

A minimal example

class base_tx;
  rand bit [7:0] data;
  virtual function void print();
    $display("base_tx data=%0h", data);
  endfunction
endclass

class ext_tx extends base_tx;
  rand bit [3:0] id;
  virtual function void print();
    $display("ext_tx data=%0h id=%0d", data, id);
  endfunction
endclass

module tb;
  base_tx h;        // handle of the base type
  ext_tx  e;
  initial begin
    e = new();  void'(e.randomize());
    h = e;           // base handle points to a derived object
    h.print();       // runs ext_tx::print because print() is virtual
  end
endmodule

If print() were not declared virtual, h.print() would call base_tx::print(), because the compiler would bind the call to the handle’s type. That single keyword is the difference between static and dynamic dispatch.

The polymorphism diagram

Think of it as a tree: base_tx at the top, ext_tx and other derived classes below. A handle of the parent type can point at any node in the subtree beneath it. A call to a virtual method travels to the node the object actually belongs to. Casting moves you up the tree for free (assigning a derived object to a base handle) and down the tree only with a checked $cast.

Casting between handle types

base_tx b = new();
ext_tx  e;
if (!$cast(e, b))          // fails: b holds a base_tx, not an ext_tx
  $display("cast failed, as expected");

base_tx b2 = new ext_tx(); // actually an ext_tx behind a base handle (illustrative)
if ($cast(e, b2))          // succeeds: the object really is an ext_tx
  e.print();

$cast checks at run time that the object is compatible with the target handle type; assigning downwards without it is a compile error.

Why UVM depends on polymorphism

  • Drivers and monitors are written for a base transaction class and work with any derived transaction.
  • The UVM factory creates objects by type name and can be told to substitute a derived type (set_type_override), which only works because the environment holds base-class handles.
  • Virtual methods in components (build_phase, run_phase, write) are overridden in user classes and called polymorphically by the framework.
  • Sequences are started through base-class handles, so a test can swap stimulus without touching the sequencer.

Common mistakes

  • Forgetting virtual on a method that is overridden, so the base version runs unexpectedly.
  • Declaring data members in the derived class and expecting them to be visible through a base handle; only the base class’s members are visible until you $cast down.
  • Using super.method() inconsistently, so a derived override skips the base behaviour it should extend.
  • Changing a virtual method’s signature in the derived class, which creates a new method instead of an override.

Learn SystemVerilog OOP for verification

Classes, inheritance, polymorphism, randomisation and the UVM framework built on them are the core of our ASIC design verification course. See also the UVM testbench tutorial and Verilog vs SystemVerilog.

Frequently asked questions

What is polymorphism in SystemVerilog?

The ability for a base-class handle to refer to a derived-class object, with virtual method calls resolved at run time to the derived class’s implementation.

What does the virtual keyword do?

It makes a method dispatch dynamically, based on the object’s actual class rather than the handle’s declared type.

What is $cast used for?

To assign a base-class handle to a derived-class handle safely, with a run-time check that the object really is of the derived type.

Why is polymorphism important in UVM?

It allows components to be written against base types and extended or replaced through the factory without changing the environment.

What is the difference between static and dynamic binding?

Static binding resolves a method call at compile time from the handle type; dynamic binding (virtual methods) resolves it at run time from the object type.

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

Ask the Admin Team

Drop your basic question in comments: eligibility, prerequisites, tools, fee range, and placement support.

Our team reviews and responds regularly.

Tags :
Share This :
Next batch starts 28th October 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%
Popular: VLSI Course Fees · Learn VLSI From Scratch · VLSI Training With Job Support · Best VLSI Training Institute · VLSI Internship 2026 · Upcoming Batches
Cities: VLSI Training Institute in Hyderabad · VLSI Training Institute in Bangalore · VLSI Training in Noida & Delhi NCR · VLSI Training in Pune
Hi! Ask me about courses, fees, batches or discounts. ×
BANGALORE
HYDERABAD