Verilog系列:System中基类和派生类之间的赋值
在SystemVerilog的具体应用中,经常会遇到派生类和基类之间相互指向异常导致编译出现问题.一般情况下,赋值符号左右两侧的表达式都源自同一个类型,虽然派生类源自基类,有些朋友可能认为两者应该属于同一类型,可以相互赋值,然而实际应用中的情况与我们想象的并不一样.下面我们将通过具体示例对基类和派生类之间相互赋值具体问题进行说明.
SystemVerilog中派生类(derived class)继承于基类(baseclass),基类的成员也是派生类的成员,派生类可以重定义其基类的成员还可以定义新成员(这就像基类为父亲,派生类为子女,子女一般都具有父亲的特征,当然子女也可以具有父亲没有的特征).派生类中定义的与基类同名的成员一般会屏蔽基类中对应成员的特性,但是被屏蔽的成员可以通过作用域符号进行访问.基类句柄可以指向其任意派生类,但是派生类的句柄不能直接指向其基类,主要原因是派生类可能具有基类中并不存在的某些成员.
【示例】基类指向派生类
【仿真结果】
31行到39行部分,p0继承于p,p0除了可以访问其本身的成员外还可以访问其基类p中的成员.又因为get_obj_v声明为virtual,虽然派生类中存在该方法的重载,但是具体调用的是基类还是派生类中定义的方法由句柄指向对象的类型决定.所以p调用的是基类中的get_obj_v,而p0调用的是派生类中的get_obj_v.
40行,p指向了其子类.因为get_obj并没有在声明时指定为virtual,所以在具体调用的是基类中的方法还是派生类中的方法由调用该方法是具体的句柄类型决定.此例中,虽然40行p指向了p0,但是p调用的方法还是p对应类型中定义的get_obj方法(不是派生类p0中定义的).相反的,因为get_obj_v声明为了virtual,所以父类中的get_obj_v被子类中的get_obj_v重载,此时p访问的是其指向对象对应类型中定义的get_obj_v.特别需要注意上例中46行,虽然p指向了p0,但是不能访问p0中的非继承于基类的方法.
【示例】派生类指向基类
【仿真结果】
如上述代码中30行被注释部分,虽然在29行已经使p指向了p0(p0和p1位同一类型),但是p1是p的派生类,不能将p赋给p1.那么如何实现派生类句柄指向基类句柄呢?在SystemVerilog中如果基类句柄确实指向一个子类对象,那么可以通过$cast(存在函数function和任务task两种方式,可根据具体需要选择使用)实现派生类句柄指向基类,如上述代码31行所示.
代码中使用的$cast存在两种原型,如下:
当将$cast作为一个任务来使用的时候,SystemVerilog会在运行的时候检查源对象类型,如果跟目的对象类型不匹配则给出一个错误报告.当$cast作为函数使用时,SystemVerilog 做类型检查,但是在失配时不再输出错误信息,而是返回值为0表示类型不兼容.反之返回一个非零值.
在进行类对象之间赋值操作时,一定要注意赋值表达式左右两侧句柄的类型,具有继承关系的类型可以通过适当的转换进行相互之间的赋值操作(如下图中format 1和format 2两种可行方式),不同类型之间的对象不能进行赋值操作.