In Inheritance, we saw that methods invoked by a base class handle which points to a child class instance would eventually end up executing the base class method instead of the one in child class. If that function in the base class was declared as
virtual, only then the child class method will be executed.
bc = sc; // Base class handle is pointed to a sub class bc.display (); // This calls the display() in base class and // not the sub class as we might think
We'll use the same classes from previous session and do a comparison with and without
Without virtual keyword
// Without declaring display() as virtual class Packet; int addr; function new (int addr); this.addr = addr; endfunction // This is a normal function definition which // starts with the keyword "function" function void display (); $display ("[Base] addr=0x%0h", addr); endfunction endclass module tb; Packet bc; ExtPacket sc; initial begin sc = new (32'hfeed_feed, 32'h1234_5678); bc = sc; bc.display (); end endmodule
ncsim> run [Base] addr=0xfeedfeed ncsim: *W,RNQUIE: Simulation is complete.
Note that the base class
display() function gets executed.
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.
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.
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.
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.
ncsim> run addr=0xdead data=0x12 addr=0xface data=0xab addr=0xcafe data=0xfc ncsim: *W,RNQUIE: Simulation is complete.