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
      • Class Declaration & Objects
      • Handles vs Objects
      • Constructors & super.new()
      • Shallow vs Deep Copy
      • this, Scope & Nested Classes
    • Inheritance and Polymorphism
    • 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

‹Classes, Objects & Handles
  1. Topics
  2. SystemVerilog
  3. Object-Oriented SystemVerilog for Verification
  4. Classes, Objects & Handles
  5. Constructors & super.new()

Part 2 · OOP for Verification · Intermediate

Constructors & super.new()

Constructor defaults, the super.new chain, and base-first construction order.

On this page

    Why this matters

    Every object in a test printed the name UNNAMED, and nothing failed. A derived class's constructor had skipped super.new, so the base part was built from its defaults instead of the real values.

    After this lesson you can: write one constructor with default and named arguments, forward arguments with super.new, and explain base-first construction order.

    One constructor with defaults

    Every class has exactly one constructor, named new. It cannot be overloaded, so default argument values cover the overloaded cases.

    A constructor puts the object into a valid initial state. It stores identity, builds owned sub-objects, and captures references passed in.

    The bench below builds three configurations from one constructor. Arguments can be given by position, or by name, which skips the ones in between.

    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
    class fifo_cfg;
      string       name;
      int unsigned depth;
      bit          strict;
    
      // One constructor; defaults stand in for overloads.
      function new(string name = "cfg", int unsigned depth = 4, bit strict = 1);
        this.name   = name;
        this.depth  = depth;
        this.strict = strict;
      endfunction
    endclass
    
    module tb_cfg_defaults;
      int errors = 0;
      initial begin
        fifo_cfg a;
        fifo_cfg b;
        fifo_cfg c;
        a = new();                              // every default
        b = new("big", 16);                     // strict keeps its default
        c = new(.name("loose"), .strict(0));    // named arguments skip depth
        if (a.name != "cfg" || a.depth != 4 || a.strict != 1) errors++;
        if (b.name != "big" || b.depth != 16 || b.strict != 1) errors++;
        if (c.name != "loose" || c.depth != 4 || c.strict != 0) errors++;
        $display("%s depth=%0d strict=%0d", a.name, a.depth, a.strict);
        $display("%s depth=%0d strict=%0d", b.name, b.depth, b.strict);
        $display("%s depth=%0d strict=%0d", c.name, c.depth, c.strict);
        if (errors == 0) $display("PASS: one constructor with defaults built three different configurations");
        else $fatal(1, "FAIL: %0d constructor default checks failed", errors);
        $finish;
      end
    endmodule
    Terminal
    cfg depth=4 strict=1
    big depth=16 strict=1
    loose depth=4 strict=0
    PASS: one constructor with defaults built three different configurations

    super.new goes first

    class axi_req extends base_req makes axi_req a derived class: it has everything base_req has, plus its own fields. The next topic teaches inheritance properly; here only one rule matters, how the two constructors run.

    Constructing a derived object must also initialize its base part. The derived constructor therefore calls super.new as its first statement.

    An omitted call inserts an implicit super.new with no arguments. That call works only when the parent takes no arguments or every argument has a default.

    Parent constructor

    Child omits super.new

    Result

    Has a required argument

    Implicit super.new supplies none

    Compile error

    All arguments defaulted

    Implicit super.new uses defaults

    Builds, with possibly wrong values

    Explicit super.new(name)

    Nothing omitted

    Parent initialized from real values

    design.sv
    1
    2
    3
    4
    5
    6
    7
    // bad-example
    class axi_bad extends base_req;
      int unsigned qos;
      function new(string name = "axi_bad");
        this.qos = 0; // compile error: implicit super.new() supplies no argument
      endfunction
    endclass

    Silent defaults are worse than errors

    Predict first The parent's constructor is new(string name = "UNNAMED"). A child's constructor forgets super.new(name). What is the name after new("s0")?

    UNNAMED. The child's constructor never passed s0 on, so the implicit super.new() ran with the parent's default. It compiles, it runs, and every object carries the wrong name.

    A compile error points at the missing call. Defaulted parent arguments instead build an object that carries the wrong name or config and keeps simulating.

    Child constructor

    Base name after new("s0")

    Verdict

    Omits super.new

    UNNAMED

    Silent trap: the forwarded name is lost

    Calls super.new(name)

    s0

    Correct: the parent sees the real value

    Testbench

    One self-contained block holds both hierarchies and the checks. Forwarding works, the constructor body sees initialized base state, and the silent variant keeps its default.

    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
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    class base_req;
      string name;
      function new(string name); // REQUIRED argument, no default
        this.name = name;
      endfunction
    endclass
    
    class axi_req extends base_req;
      int unsigned qos;
      int order_ok;
      function new(string name = "axi_req");
        super.new(name);
        if (this.name != name) order_ok = 0;
        else order_ok = 1;
        this.qos = 0;
      endfunction
    endclass
    
    class base_dflt;
      string name;
      function new(string name = "UNNAMED");
        this.name = name;
      endfunction
    endclass
    
    class child_dflt extends base_dflt;
      function new(string name = "child2");
        // forgot super.new(name): implicit super.new() runs instead
        // object is built, but base name stays "UNNAMED"
      endfunction
    endclass
    
    class child_fwd extends base_dflt;
      function new(string name = "child2");
        super.new(name);
      endfunction
    endclass
    
    module tb_l3_chain;
      int errors = 0;
      initial begin
        axi_req a;
        axi_req d;
        child_dflt s;
        child_fwd f;
        a = new("a0");
        if (a.name != "a0") errors++;
        if (a.qos != 0) errors++;
        if (a.order_ok != 1) errors++;
        d = new();
        if (d.name != "axi_req") errors++;
        s = new("s0");
        if (s.name != "UNNAMED") errors++;
        f = new("f0");
        if (f.name != "f0") errors++;
        if (errors == 0) $display("PASS: super.new forwarding and silent-default trap behave as specified");
        else $fatal(1, "FAIL: constructor chain checks");
        $finish;
      end
    endmodule
    Terminal
    PASS: super.new forwarding and silent-default trap behave as specified
    The base part is built first, through super.new, and only then does derived code run. That is also why a constructor should not call methods a derived class overrides.

    Common pitfall

    Doing heavy work in a constructor runs before the test can configure anything. Keep constructors to identity, defaults, and owned sub-objects, and never call a virtual method from new.

    Interview

    The chaining trio recurs in interviews.

    • Constructors cannot be virtual: new always builds exactly the class it names.

    • Forgotten super.new: a compile error with required parent args, silent defaults without.

    • Three-level order: grandparent, parent, child, always base first.

    Check yourself A derived constructor omits super.new, and the parent needs one argument. What happens?

    A compile error. The implicit super.new supplies no arguments.

    Check yourself The same omission, but every parent argument has a default. What happens?

    It compiles. The parent initializes from defaults, which silently carries the wrong name or config.

    Remember

    • A class has exactly one constructor; default arguments replace overloading.

    • A derived constructor calls super.new first; omit it and super.new() with no arguments runs.

    • With required parent arguments a missing super.new is a compile error; with defaults it is a silent wrong value.

    Rule of thumb: forward every argument the parent needs, explicitly, on the first line.

    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. Icarus 13 cannot run the ones that compare class handles or keep a queue inside a class.

    Related topics

    • Class Declaration & Objects

    • Inheritance & Polymorphism

    Previous

    37 / 259

    Next: Shallow vs Deep Copy

    Up next

    Up nextShallow vs Deep Copy

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Class Declaration & Objects
    • this, Scope & Nested Classes