Polymorphism allows the use of a variable of the base class type to hold subclass objects and to reference the methods of those subclasses directly from the superclass variable. It also allows a child class method to have a different definition than its parent class if the parent class method is
virtual in nature.
Parent and Child Assignment
A class handle is just a container to hold either parent or child class objects. It is important to understand how parent class handles holding child objects and vice-versa behave in SystemVerilog.
Assign Child Class to Base Class
Taking the same example from Inheritance, we'll assign a sub/child class instance sc to a base class handle bc.
module tb; Packet bc; // bc stands for BaseClass ExtPacket sc; // sc stands for SubClass initial begin sc = new (32'hfeed_feed, 32'h1234_5678); // Assign sub-class to base-class handle bc = sc; bc.display (); sc.display (); end endmodule
ncsim> run [Base] addr=0xfeedfeed [Child] addr=0xfeedfeed data=0x12345678 ncsim: *W,RNQUIE: Simulation is complete.
Even though bc points to the child class instance, when
display() function is called from bc it still invoked the
display() function within the base class. This is because the function was called based on the type of the handle instead of the type of object the handle is pointing to. Now let's try to reference a subclass member via a base class handle for which you'll get a compilation error.
module tb; Packet bc; // bc stands for BaseClass ExtPacket sc; // sc stands for SubClass initial begin sc = new (32'hfeed_feed, 32'h1234_5678); bc = sc; // Print variable in sub-class that is pointed to by // base class handle $display ("data=0x%0h", bc.data); end endmodule
$display ("data=0x%0h", bc.data); | ncvlog: *E,NOTCLM (inheritance.sv,49|36): data is not a class item.
Assign Base Class to Child Class
It is illegal to directly assign a variable of a superclass type to a variable of one of its subclass types and hence you'll get a compilation error.
module initial begin bc = new (32'hface_cafe); // Assign base class object to sub-class handle sc = bc; bc.display (); end endmodule
sc = bc; | ncvlog: *E,TYCMPAT (inheritance.sv,56|12): assignment operator type check failed (expecting datatype compatible with 'class $unit::ExtPacket' but found 'class $unit::Packet' instead).
$cast can be used to assign a superclass handle to a variable of a subclass type provided the superclass handle refers to an object that is assignment compatible with the subclass variable.
module initial begin bc = new (32'hface_cafe); // Dynamic cast base class object to sub-class type $cast (sc, bc); bc.display (); end endmodule
Although the code will compile well, it will have a run-time simulation error because of the failure of
$cast. This is because bc is not pointing to an object that is compatible with sc.
ncsim> run $cast (sc, bc); | ncsim: *E,BCLCST (./inheritance.sv,57|10): Invalid cast: a value with the class datatype '$unit_0x06d772f8::Packet' cannot be assigned to a class variable with the datatype '$unit_0x06d772f8::ExtPacket'. [Base] addr=0xfacecafe ncsim: *W,RNQUIE: Simulation is complete.
Let's make bc point to another subclass called sc2 and try the same thing. In this case, bc simply acts like a carrier.
initial begin ExtPacket sc2; bc = new (32'hface_cafe); sc = new (32'hfeed_feed, 32'h1234_5678); bc = sc; // Dynamic cast sub class object in base class handle to sub-class type $cast (sc2, bc); sc2.display (); $display ("data=0x%0h", sc2.data); end
ncsim> run [Child] addr=0xfeedfeed data=0x12345678 data=0x12345678 ncsim: *W,RNQUIE: Simulation is complete.
A method in the parent class can be declared as
virtual which will enable all child classes to override the method with a different definition, but the prototype containing return type and arguments shall remain the same.
class Base; rand bit [7:0] addr; rand bit [7:0] data; // Parent class has a method called 'display' declared as virtual virtual function void display(string tag="Thread1"); $display ("[Base] %s: addr=0x%0h data=0x%0h", tag, addr, data); endfunction endclass class Child extends Base; rand bit en; // Child class redefines the method to also print 'en' variable function void display(string tag="Thread1"); $display ("[Child] %s: addr=0x%0h data=0x%0h en=%0d", tag, addr, data, en); endfunction endclass
Click here to learn more on Virtual Methods
Rules to follow
- Assignment of derived class handle to base class handle is allowed.
- Assignment of base class handle to derived class handle is NOT allowed and results in compilation error.
base b = new; child c = new; b = c; // Allowed c = b; // Compilation Error
$castreturns 0 if the cast failed, so use the return type to throw an error. Use
assertto ensure that the cast is successful.
base b = new; child c = new; if (! $cast(c, b)) $error("Cast failed !"); assert($cast(c, b)) else $error("Cast failed !");