Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • Start Here6
  • SystemVerilog Language Foundations28
  • Object-Oriented SystemVerilog for Verification30
    • Classes, Objects & Handles
    • Inheritance and Polymorphism
      • extends and super
      • Virtual dispatch
      • Casting with $cast
      • Contracts and polymorphic containers
    • Static, Encapsulation & Parameterized Classes
    • Virtual Interfaces: the Class-to-Pins Bridge
    • Events, Semaphores, Mailboxes and Processes
    • OOP Patterns for Testbenches
  • Constraint Randomization — Interview-Critical Deep Dive36
  • SystemVerilog Assertions — Interview-Critical Deep Dive40
  • Functional Coverage in SystemVerilog22
  • Testbench Architecture in SystemVerilog23
  • Advanced Language & Integration25
  • Senior & Interview Preparation21
  • Principal-Level Verification28
Loading lesson

‹Inheritance and Polymorphism
  1. Topics
  2. SystemVerilog
  3. Object-Oriented SystemVerilog for Verification
  4. Inheritance and Polymorphism
  5. Contracts and polymorphic containers

Part 2 · OOP for Verification · Intermediate

Contracts and polymorphic containers

Abstract bases, interface contracts, mixed queues, and factory creation.

On this page

    Why this matters

    A new transaction type was added, and a forgotten method ran as a silent empty default. A pure virtual method would have made it a compile error.

    After this lesson you can: write a virtual class with pure virtual methods, implement interface classes, and drive a mixed queue through base handles.

    Bases that cannot be built

    A virtual class cannot be constructed directly, but handles of its type work normally. Use one when the base exists only to define a shape, such as a generic stimulus item.

    A pure virtual method declares a prototype with no body. Every concrete subclass must implement it, which turns a missing method from a runtime mystery into a compile error.

    Kind

    Carries

    Adopted by

    Gives

    virtual class

    Data plus pure and concrete methods.

    One extends parent.

    Shared implementation with mandatory hooks.

    interface class

    Pure virtual prototypes only.

    Many implements contracts.

    Multiple role promises, no state.

    Contracts without a parent

    A class extends exactly one parent but may implement any number of interface classes. That combination recovers multiple inheritance of contract without data-layout ambiguity.

    Code environments against the contract, not the concrete class. Tests then inject any driver that satisfies it, which is the hand-rolled ancestor of factory overrides.

    Predict first In the next listing, mon extends stim_item and implements resettable. A resettable handle r points at a mon whose seen is 3. After r.do_reset(), what does m.check() return?

    0. do_reset() cleared seen in the same object, and mon's check() returns 1 only when seen is above 0.

    Abstract handles with interface contracts, proven through a resettable monitor:

    class.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    virtual class stim_item;
      string item_name;
    
      function new(string name_ = "stim_item");
        item_name = name_;
      endfunction
    
      pure virtual function bit check();
    
      virtual function void announce();
        $display("[%s] sending", item_name);
      endfunction
    endclass
    
    class eth_frame extends stim_item;
      bit [47:0] dst;
    
      function new();
        super.new("eth_frame");
      endfunction
    
      virtual function bit check();
        return dst != 48'h0;
      endfunction
    endclass
    
    interface class reportable;
      pure virtual function string report();
    endclass
    
    interface class resettable;
      pure virtual task do_reset();
    endclass
    
    class mon extends stim_item implements reportable, resettable;
      int unsigned seen = 0;
    
      function new();
        super.new("mon");
      endfunction
    
      virtual function bit check();
        return seen > 0;
      endfunction
    
      virtual function string report();
        return $sformatf("mon: %0d seen", seen);
      endfunction
    
      virtual task do_reset();
        seen = 0;
      endtask
    endclass
    
    Terminal
    [mon] sending
    PASS: abstract handle dispatches check, reset contract clears state

    One queue and one factory

    A queue of base handles holds mixed derived objects, since each element is a reference and every derived object is its base. Consumers should call virtual methods and stay type-blind.

    Reach for $cast only for genuinely type-specific side paths, such as sampling AXI-only fields into plain variables. The factory mirror builds concrete types behind a base-handle return.

    The factory builds only the requested type. It is declared automatic, so every call constructs a fresh object.

    A mixed queue with virtual checks plus a factory that returns base handles, proven over four objects.

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    class bus_txn;
      bit [31:0] addr;
    
      virtual function bit check();
        return addr[1:0] == 2'b00;
      endfunction
    
      virtual function void print();
        $display("BUS addr=%0h", addr);
      endfunction
    endclass
    
    class axi_txn extends bus_txn;
      bit [3:0] qos;
    
      virtual function bit check();
        if (!super.check()) return 0;
        return qos != 0;
      endfunction
    
      virtual function void print();
        $display("AXI addr=%0h qos=%0d", addr, qos);
      endfunction
    endclass
    
    class err_txn extends bus_txn;
      virtual function bit check();
        return 0;
      endfunction
    
      virtual function void print();
        $display("ERR addr=%0h", addr);
      endfunction
    endclass
    
    typedef enum {PLAIN, AXI, ERR} txn_kind_e;
    
    function automatic bus_txn make_txn(txn_kind_e kind);
      case (kind)   // build only the requested type
        AXI: begin axi_txn ax = new(); return ax; end
        ERR: begin err_txn er = new(); return er; end
        default: begin bus_txn plain = new(); return plain; end
      endcase
    endfunction
    
    Terminal
    BUS addr=1000
    AXI addr=2000 qos=3
    ERR addr=0
    AXI addr=0 qos=0
    PASS: mixed queue dispatches check per type and factory made 4 kinds

    Common mistakes

    Common pitfall

    An interface class holds no data and no method bodies, and it is unrelated to the signal-bundle interface used with DUT pins. Empty default bodies instead of pure virtual methods let forgotten overrides run as silent no-ops.

    Interview

    Likely questions: abstract versus interface class, what pure virtual buys, and how SV emulates multiple inheritance.

    • Abstract class keeps data and partial implementation under one extends; interface class is a pure multi-implements contract.

    • Pure virtual makes implementation mandatory and checked at compile time.

    • One extends chain for identity, implements for roles, composition for reusable behavior.

    Check yourself A monitor must be both resettable and reportable while extending its protocol base. How is that written?

    One extends plus two implements. The single parent keeps identity while each interface adds a checked role contract.

    Check yourself A consumer walks a base-handle queue with a long if-else chain of $casts. What is the cleaner shape?

    Move the behavior into a virtual method. Consumers stay type-blind and new transaction flavors need no consumer changes.

    Remember

    • A virtual class cannot be built; pure virtual methods must be implemented.

    • A class extends one parent and may implement many interface classes.

    • Mixed queues stay type-blind through virtual methods; $cast is for side paths.

    Rule of thumb: make the base promise what every subclass must provide.

    How this was checked

    Run with Verilator 5.048 (--binary --timing) on 2026-10-18; every bench printed the PASS line shown, with no warnings. These class benches were run on Verilator only.

    A factory function that is automatic builds a new object on every call; in a static function its initialisers would run once (IEEE 1800 6.21) and hand every caller the same object.

    Related topics

    • Next topic: Class Features

    Previous

    43 / 259

    Next: Static, Encapsulation & Parameterized Classes

    Up next

    Up nextStatic, Encapsulation & Parameterized Classes

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • extends and super
    • Virtual dispatch