先说概念:
虚方法(virtual):在父类中的方法名前添加“ virtual ”关键字,实现父类和子类方法的动态绑定(在SV中称为动态方法查找)。
动态查找:利用类的多态性,在设计和使用类的时候,不需担心句柄指向的对象类型到底是父类还是子类,直接能够优先去调用实例对象本身对应的方法。
类型转换:子类句柄可以赋给父类句柄,因为子类对象通常包含父类对象的所有,父类句柄却不能直接赋给子类句柄,故需要类型转换。使用系统函数$cast(),它是一个带返回值的函数,如果转化成功,$cast(target, source)会返回1,如果转化失败,$cast(target, source)会返回0,但是不会报错。所以通过if语句或者断言assert来判断是否转化成功,然后进行下一步操作。
为什么父类句柄经常需要转换为子类句柄?
因为父类句柄在指向一个子类对象的时候,它只能访问子类中,父类的那部分成员。如果想访问子类中的成员/方法,则必须要转换为子类句柄才能访问。
虚方法如何声明?该在哪里声明?
先说目的,虚方法声明是为了父类句柄访问子类对象的成员/方法时,不经过句柄转换$cast()这一麻烦操作。 那么我们可以通过在父类中对以后可能会被子类继承的方法前,声明 “virtual”关键词。
这样,当程序调用该方法时,SystemVerilog会根据句柄指向 对象 的类型,而非 句柄 的类型,来动态决定调用什么方法(即动态调用)。如果该方法在父类中没有声明virtual,则SV会根据句柄的类型来调用同名方法,起不到效果了。
需注意:
1. 上述使用虚方法来实现方法的动态调用时,子类中相应的方法的方法名、方法的返回类型以及方法的参数,必须和父类中的方法保持一致,否则子类定义的方法就不叫继承,应该叫重写(override)了。
2. 一般在父类中通过virtual声明虚方法,只需声明一次即可,而其子类则无需再次声明。子类及其后续子类的同名方法,添不添加,均视为虚方法属性。
3. 除了new()函数不能添加virtual,父类的其它方法均可以添加virtual声明,但类的成员变量不能添加virtual声明。换句话说——父类句柄想访问子类对象中成员,只能通过cast()转换。