Inheritance is a concept in OOP that allows us to extend a class to create another class and have access to all the properties and methods of the original parent class from the handle of a new class object. The idea behind this scheme is to allow developers add in new properties and methods into the new class while still maintaining access to the original class members. This allows us to make modifications without touching the base class at all.
Example
ExtPacket is extended and hence is a child class of Packet. Being a child class, it inherits properties and methods from its parent. If there exists a function with the same name in both the parent and child class, then its invocation will depend on the type of the object handle used to call that function. In the example below, both Packet and ExtPacket have a function called display()
. When this function is called by a child class handle, the child class display()
function will be executed. If this function is called by a parent class handle, then the parent class display()
function will be executed.
In a previous post, key topics on class handles and objects were discussed which is essential to understand how shallow copy and deep copy works.
Click here to refresh concepts in class handles and objects !
The this
keyword is used to refer to class properties, parameters and methods of the current instance. It can only be used within non-static methods, constraints and covergroups. this
is basically a pre-defined object handle that refers to the object that was used to invoke the method in which this
is used.
Example
A very common way of using this
is within the initialization block.
class Packet;
bit [31:0] addr;
function new (bit [31:0] addr);
// addr = addr; // Which addr should get assigned ?
this.addr = addr; // addr variable in Packet class should be
// assigned with local variable addr in new()
endfunction
endclass
Unless there is ambiguity in assignment, use of this
keyword is not generally needed for specifying access to class members in methods.
Each class instance would normally have a copy of each of its internal variables.
class Packet;
bit [15:0] addr;
bit [7:0] data;
function new (bit [15:0] ad, bit [7:0] d);
addr = ad;
data = d;
$display ("addr=0x%0h data=0x%0h", addr, data);
endfunction
endclass
module tb;
initial begin
Packet p1, p2, p3;
p1 = new (16'hdead, 8'h12);
p2 = new (16'hface, 8'hab);
p3 = new (16'hcafe, 8'hfc);
end
endmodule
Each of the class objects p1, p2, p3 will have addr and data variables within it.
Simulation Logncsim> run addr=0xdead data=0x12 addr=0xface data=0xab addr=0xcafe data=0xfc ncsim: *W,RNQUIE: Simulation is complete.
A constructor is simply a method to create a new object of a particular class data-type.
Constructors
C/C++ requires complex memory allocation techniques and improper de-allocation could lead to memory leaks and other behavioral issues. SystemVerilog, although not a programming language, is capable of simple construction of objects and automatic garbage collection.
When class constructor is explicity defined
// Define a class called "Packet" with a 32-bit variable to store address
// Initialize "addr" to 32'hfade_cafe in the new function, also called constructor
class Packet;
bit [31:0] addr;
function new ();
addr = 32'hfade_cafe;
endfunction
endclass
module tb;
// Create a class handle called "pkt" and instantiate the class object
initial begin
// The class's constructor new() fn is called when the object is instantiated
Packet pkt = new;
// Display the class variable - Because constructor was called during
// instantiation, this variable is expected to have 32'hfade_cafe;
$display ("addr=0x%0h", pkt.addr);
end
endmodule
In the example above, variable declaration creates an object of class Packet and will automatically call the new()
function within the class. The new()
function is called a class constructor and is a way to initialize the class variables with some value. Note that it does not have a return type and is non-blocking.
ncsim> run
addr=0xfadecafe
ncsim: *W,RNQUIE: Simulation is complete.