Inheritance in SV
In previous article we learnt how to write classes and objects in System Verilog. In this article we will focus on learning about the inheritance of classes in System Verilog. We will learn how to create a child class and add additional functionalities in the child class. We will also see casting of objects from child class to parent class and vice versa.
Sub classes or child classes are classes which are derived from other class which are known as parent or super class. In verification, we would come across various scenarios were we want to have some base reference class and then slowly build upon that super/base class.
Child class are known as sub class, derived class.
In System Verilog
extend keyword is used to create a child class. We use this keyword in class declaration after the name of the child class.
class <class name> extends <base_class_name>; endclass
In previous article we saw about
super keyword is kind of like
this keyword except it is used to access property or method present in parent class.
class abc extends xyz; function test(); super.test1(); endfunction endclass
In above code, test method of child class abc will call the test1 method of parent class xyz.
It is not necessary to use the super keyword when method name is unique b/w parent and child class. In the above example, even if we don’t use keyword, it will work as expected. Super keyword is mainly used when method name are common in parent and child or when we do function overriding which we will learn later.
When a constructor of child class is called it automatically calls the new class of parent class, i.e., super.new() is by default the first thing called inside constructor of child class. If the constructor of parent class requires some arg, then we need to explicitly call parent class constructor and pass the arg.
class parent; int a, b; function void print(); $display("a = $-1d, b = %0d", a, b); endfunction endclass class child extends parent; int c; function void print(); super.print(); $display("c = %-1d", c); endfunction endclass
In the above example, we are creating a child class
child from parent class
parent. In child class we can access all the properties and methods defined in the parent class and the additional properties which we have declared in child class.
The example which we saw in previous section was an example of single inheritance, i.e., there was a child class and parent class. But in multi-level inheritance child class can also be the parent of another child. This can be understood from the analogy of family tree.
This concept allows us to create a very complex code structure, where we can create a new level of class hierarchy and add additional functionalities to the class without touching the parent class.
Multi-level inheritance should not be confused with multiple inheritance. In multiple inheritance a child class can have multiple parent class. This is not supported in SV and thus would give error if we try to inherit multiple classes.
In multi-level inheritance it is not allowed to reach class higher than the immediate parent class. This means that
super.super.new()or similar are not allowed.
class c1; endclass class c2 extends c1; endclass class c3 extends c2; endclass
Type casting refers to casting data of one type to another. In simple terms, it means to covert variable/object of one data type to another. In System Verilog or any other OOP languages, classes are considered as data type and object conversion is allowed b/w parent and child class data types.
These are most often required in scenarios where some component might have args defined in parent class data type and we have an object of child class data type or vice-versa. To deal with these types of scenarios we have to use typecasting.
Object of parent class type can be converted to child class type implicitly by compiler and thus we don’t need to do anything. But vice-versa is not allowed implicitly. We need to do explicit type conversion using
$cast() system method.
It is recommended to use
$cast()always to cast objects as it returns a bit value to indicate whether cast was successful or not. Thus, it can be used to handle any cast errors properly and avoid any unexpected run-time errors.
We will learn about type casting in detail after few articles. For now, understanding the basic need for type casting would be enough.
class parent; int x =5; function new(); $display("inside new of parent class"); endfunction //new() task printf(); $display("This is parent class"); endtask endclass //parent class subclass extends parent; function new(); $display("inside new of child class"); endfunction //new() task printf(); $display("This is subclass"); $display("calling parent's printf method from subclass"); super.printf(); endtask endclass //subclass extends parent module inheritence; initial begin parent p; subclass s; p=new(); s=new(); s.x = 10; $display("Value of x using p: %d", p.x); $display("Value of x using s: %d", s.x); p.printf(); s.printf(); end endmodule
# inside new of parent class # inside new of parent class # inside new of child class # Value of x using p: 5 # Value of x using s: 10 # This is parent class # This is subclass # calling parent's printf method from subclass # This is parent class
In above example, please note that the constructor of child class automatically called the parent class constructor and thus we are seeing the output from new method of parent class 2 times.Try this code in EDA Playground
In this article we learnt how to create a child class and how to access the parent class variables/methods from the child class. Also, we learnt about the super keyword which plays a very important role specially in verification frameworks like UVM. In the next article we will learn about polymorphism in System Verilog and how to implement it