Day 7 taught you classes and objects. Now unlock the true power of OOP: inheritance and polymorphism. Create a hierarchy of related classes where common behavior lives in a base class, specialized behavior lives in derived classes, and a single base class reference can point to any derived type, calling the correct method automatically.
Inheritance allows a derived class to extend a base class using extends. The derived class inherits all properties and methods and can add new ones, override methods, or call the base version with super.
class derived_class extends base_class; // Inherits all properties and methods // Can add new properties and methods // Can override virtual methods from base endclass
Polymorphism means "many forms". A single base class reference can point to objects of different derived types. When you call a method, the correct version (based on the actual object, not the reference type) executes. This requires the method to be virtual in the base class.
class transaction;
virtual function void do_transaction();
$display("Base: generic transaction");
endfunction
endclass
class read_transaction extends transaction;
virtual function void do_transaction();
override;
$display("Derived: reading from address");
endfunction
endclass
transaction tr = new read_transaction();
tr.do_transaction(); // Calls derived version!
// Output: "Derived: reading from address"
If the base method is not virtual, the base version is always called:
transaction tr = new read_transaction();
tr.do_transaction(); // Calls BASE version — wrong!
// Output: "Base: generic transaction"
Mark overridden methods with override (optional but recommended). Use super.method() to call the parent version. This is useful when extending rather than replacing base behavior:
class derived extends base;
virtual function void setup();
override;
super.setup(); // Call base version first
$display("Derived setup complete");
endfunction
function new();
super.new(); // Call base constructor
endfunction
endclass
class transaction;
rand logic [15:0] addr;
rand logic [7:0] data;
logic valid;
function new();
addr=0; data=0; valid=0;
endfunction
virtual function void do_transaction();
$display("Generic TX: addr=%h data=%h", addr, data);
endfunction
virtual function void display();
$display(" addr=%h data=%h valid=%b", addr, data, valid);
endfunction
endclass
class read_transaction extends transaction;
logic [7:0] read_data;
function new();
super.new();
read_data=0;
endfunction
virtual function void do_transaction();
override;
$display("READ TX: addr=%h", addr);
endfunction
virtual function void display();
override;
super.display();
$display(" + read_data=%h", read_data);
endfunction
endclass
class write_transaction extends transaction;
logic [3:0] byte_enable;
function new();
super.new();
byte_enable=4'b1111;
endfunction
virtual function void do_transaction();
override;
$display("WRITE TX: addr=%h data=%h be=%b", addr, data, byte_enable);
endfunction
virtual function void display();
override;
super.display();
$display(" + byte_enable=%b", byte_enable);
endfunction
endclass
module transaction_demo;
initial begin
// Create objects
read_transaction rd = new();
write_transaction wr = new();
rd.addr=16'h1000;
wr.addr=16'h2000; wr.data=8'hAA;
// Store in queue of base class handles
transaction q[$];
q.push_back(rd);
q.push_back(wr);
// Polymorphic calls — each calls its own version
foreach (q[i]) begin
q[i].do_transaction();
q[i].display();
end
$finish;
end
endmoduleclass derived extends base — derived inherits all properties and methods from base.super.method() calls the parent class version, useful for extending behavior.Inheritance allows a derived class to extend a base class. The derived class inherits all properties and methods from the base and can add new ones or override existing ones to customize behavior.
Polymorphism allows a base class reference to point to derived objects. Virtual methods ensure the correct derived version is called, not the base version, based on the actual object type.
Virtual enables dynamic dispatch: the method called is determined by the actual object type at runtime, not the reference type. Without virtual, the base version is always called (static dispatch).
Use super.method() to call the parent class version. For constructors: super.new(). This is useful when the derived class wants to extend rather than replace the base behavior.