SystemVerilog中的多态和虚方法

封装可以隐藏实现细节,使代码模块化,继承可以扩展已经存在的代码模块,目的都是为了代码重用。多态是为了实现接口的重用。在SystemVerilog子类和父类之间多个子程序使用同一个名字的现象称为SystemVerilog的“多态polymorphism”特征子类从父类扩展创建之后子类就继承了父类的属性和方法这是SystemVerilog的继承特征但是这个继承特征需要遵循一定的规则

子类继承父类的所有属性local除外和方法;

子类可以添加新的属性和方法;

子类可以重写父类中的属性和方法;

如果父类的一个方法被重写,子类必须保持和父类的原定义有一致的参数;

子类可以通过super不能使用super.super方式操作符引用父类中的方法和成员;

被声明为local的属性或方法只能对自身可见,而对于外部和子类不可见;

被声明为protected的属性或方法,对外部不可见,对于自身和子类可见

我们知道因为继承的特性子类可以访问父类的属性当子类对父类的方法进行重写子类句柄访问的是重写的方法那么当父类句柄指向子类时是否可以通过父类句柄访问子类的属性和方法呢默认情况下父类句柄是不能直接访问子类的方法或者重写父类的方法

示例

【仿真结果】

注释掉29行后,虽然pkt指向了spkt,但是pkt还是不能访问其子类spkt中的vdisp方法,仿真会报如下错误。

示例中通过父类句柄直接访问子类的属性是不能访问到子类新增加的方法那么通过父类句柄可以访问被子类重写的方法吗?请看下例。

【示例】

【仿真结果】

可见,虽然子类对父类中的方法进行了重写,并且将父类句柄指向了子类对象,但是父类句柄和子类句柄还是访问各自类型中的方法。那么如何可以实现通过父类句柄对子类重写属性的访问呢

示例


仿真结果
示例中,pkt具有如下图的属性和方法,其中vdisp为虚方法,call_vdisppkt的方法,其中调用了vdispdispcall_disp均为非虚方法。在pkt没有指向spkt时,pkt访问dispcall_dispvdispcall_vdisp四种方法都是packet中的四种方法。

spkt具有的属性如下图:


SystemVerilog中,类对象的空间分配分为两个部分(如上图所示),一部分来自父类的继承部分,一部分是重写或新增的部分。spkt访问disp时,因为disp为其父类的非virtual方法,虽然sub_packet对其进行了重写,但是当spkt对其访问时,访问的是sub_packet定义的dispvdisp访问情况同disp。当spkt访问call_disp时,因为sub_packet中没有定义call_disp,那么程序会访问内存中父类中的call_dispcall_disp是一个普通的方法,此时call_disp中调用的disp也是一个普通方法,所以此时的调用均为spkt对象中的pkt部分。当spkt仿call_vdisp时,因为call_vdisp是一个普通方法,所以此时会调用spkt中的pkt部分,但是在call_vdisp中调用的vdisppkt中的虚方法,并且该虚方法在spkt中进行了重定义,所以此时call_vdisp调用的vdispspkt中重写的vdisp。所以在spkt调用四个函数时,只有对call_disp的调用显示的是pkt中输出的信息。

pkt指向spkt之后,pkt调用dispcall_dispvdispcall_vdisp这四种方法的实际调用访问顺序如下图所示:


pkt调用这几种方法时,程序同样会找到spkt中的pkt部分,此时如果发现调用的方法是虚方法,那么就会在spkt中查找重写的对应的方法,如果确实存在重写的方法,那么此时就会调用spkt中的重写的方法。如果没有则会执行pkt部分的方法。

spkt调用dispcall_dispvdispcall_vdisp这四种方法的实际调用访问顺序如下图所示:


spkt调用这几种方法时,对于spkt中的存在的方法将会直接调用,对于spkt不存在的则会访问pkt部分,在访问pkt中的方法时,如果其调用的方法为pkt中定义的虚方法,且该方法在spkt中重写,那么此时pkt中的该方法将调用spkt中重写过得方法,如示例中对call_vdisp的调用。

通过上述几个示例,可以看到声明一种方法为虚方法的方式就是在原来方法前添加关键字virtual子类中重写的方法可以不用添加virtual关键字并且子类中重写的方法要和父类中该方法的参数和返回值一致当将父类中将要被重写的方法在声明时指定为virtual方法那么当父句柄指向子类对象的空间此时可以实现父句柄对子类重写父类方法的访问SystemVerilog中子类对象的空间分配分为两个部分,一部分来自父类的继承部分,一部分是重写或新增的部分。默认情况下,父类的方法是无法访问派生类的重写和新增部分的如果希望重写的方法被父类看到,就需要依靠本示例中的virtual方法而虚方法正是OOP中基本的多态性结构那么,哪些方法要定义为virtual方法呢?经常需要对从父类继承的方法进行一定的修改以适应其应用的需要的方法在父类中对该方法定义的时候需要添加virtual关键字将该方法声明为虚方法。

综上所述,关于虚方法我们得到以下注意事项:

  • 当使用了virtual方法,那么SystemVerilog会根据对象的类型决定调用哪个虚方法,而非句柄的类型;

  • 当没有使用virtual方法,那么SystemVerilog会根据句柄的类型决定调用哪个虚方法,而非对象的类型;

  • 如果父类的一个方法被重写,子类必须保持和父类的原定义有一致的参数

虚方法与重写的实现就是多态!当父类的对象指向不同的子类的时候,虚方法就表现出了不同的实现方法,呈现多态!


全部评论
感谢楼主分享的多态的实现
点赞 回复 分享
发布于 2022-10-09 10:28 陕西

相关推荐

牛客ID:561366855:期望薪资多少?难以相信这简历找不到工作。说明二本电子信息专业想对口就业非常难。
点赞 评论 收藏
分享
爱吃肉的伊登在写日记:好棒,27届简历能做成这个样子,但是第一个项目感觉cover住难度还是不小的,特别是二面的时候肯定要对分布式系统设计这一块儿有高出正常面试者的水平才行
点赞 评论 收藏
分享
评论
1
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务