SystemVerilog中的类的继承

描述

继承是基于类的面向对象编程(object-oriented pro - gramming)的最重要特性之一。

扩展类,简言之,就是基类的扩展。

扩展类继承了基类的所有属性和方法,并且支持在继承类中重写基类的属性和方法以及新增更多的属性和方法。

所以,继承类的好处是什么?

1、继承类对基类的复用+改进
2、基类的改动能很快地影响到所有继承类,减少公共代码的修改

例如,可以定义一个名为EthernetPacket的基类。然后定义扩展类,如EtherErrorPacket、EtherLatencyPacket等,除了继承基类的属性,还可以根据需要新增更多的新属性和方法。

 

module class_TOP( );

class base;
logic [31:0] data1;
logic [31:0] data2;
logic [31:0] busx;

function void bus;
busx = data1 | data2;
endfunction

function void disp;
$display("From Base Class :: busx OR = %h", busx);
endfunction

endclass : base

class ext extends base;
logic [31:0] data3; //add a new property
function new ( );
$display("Call base class method from extended class - 
super.disp");
super.disp;
endfunction

function void bus; //redefne function 'bus' of class 'base'
busx = data1 & data2 & data3;
//data1,data2 inherited from class 'base'
endfunction

function void disp; //redefne function 'disp' of 
class 'base'
$display("From Extended Class :: busx AND = %h",busx);
endfunction

endclass : ext

initial begin
base b1;
ext e1;
b1 = new;
e1 = new;
b1.data1 = 32'h ffff_0000;
b1.data2 = 32'h 0000_ffff;
b1.bus;
b1.disp( );
e1.data1 = 32'h 0101_1111;
e1.data2 = 32'h 1111_ff;
e1.data3 = 32'h 1010_1010;
e1.bus;
e1.disp( );
end
endmodule

 

仿真log:

 

Call base class method from extended class - super.disp
From Base Class :: busx OR = xxxxxxxx
From Base Class :: busx OR = ffffffff
From Extended Class :: busx AND = 00001010
 V C S S i m u l a t i o n R e p o r t

 

在class “base”中,我们定义了属性data1、 data2和busx,然后又定义了2个functions “bus”和“disp”

由于我们没有显式地定义构造函数new(),所以变量data1, data2和busx都会被初始化成“x”态 。

class “ext”是class “base”的继承类,所以类“ext”自然也会有属性“data1,” “data2,” 和“busx”。

同时我们在类“ext”中额外声明了属性“data3”,并且覆盖了父类中函数“bus”和“disp”的声明。

在上面的例子中,我们在扩展类"ext"中的构造函数中通过关键字“super.”来调用父类中声明的函数。所以会打印:

 

From Base Class :: busx OR = xxxxxxxx

 

在initial语句块中,我们赋值父类中的属性,然后打印出“busx.”(即data1 | data2)。然后修改扩展类中的属性,然后打印出“busx.”(覆盖过的函数data1 & data2 & data3)

仿真的log也证明了父类的函数被成功地覆盖掉了。

每一个class 都会有一个构造函数new()(隐式或者显式的),在扩展类的构造函数中,第一件事就是要去调用父类的构造函数“super.new( )”。然后如果你忘了在扩展类的构造函数中添加,编译仿真工具也会自动帮你添加的。

一般来说不需要显式地添加super.new(),但是如果构造函数带参数,那么必须要显式地添加supoer.new()

Inheritance Memory Allocation

还是那句话,理解一个语言的很多特性都需要从内存分配的角度去理解。

如果需要完全理解扩展类,就需要理解基类和扩展类中的属性和函数的内存分配。

 

module class_TOP( );
 class aa;
 int i1;
 function funAA;
 endfunction
 endclass : aa
 
 class bb extends aa;
 int i1;
 function funBB;
 endfunction
 endclass : bb
 
 initial begin
 bb b;
 b = new( );
 end
 endmodule

 


在上面的例子中,虽然我们只是调用了扩展类的构造函数“b = new( ),” ,但是实际上,我们不仅分配的类“bb”的内存空间,还分配了基类“aa”的内存空间,即使变量名称一样。

System

这个同名的变量需要通过作用域(不同的内存分配)进行区分。

  审核编辑:汤梓红

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分