一、使用$cast作类型向下转换
类型向下转换或者类型变换是指将一个指向基类的指针转换成一个指向派生类的指针。但是将一个基类对象拷贝到一个扩展类的句柄中时,因为有些属性仅存在于扩展类中,基类并不具备,所以可能导致失败。为什么说可能呢?因为将一个基类句柄赋值给一个扩展类句柄并不总是非法的,当基类句柄确实指向一个派生类对象时时允许的。$cast子程序会检查句柄所指向的对象类型,而不仅仅检查句柄本身,一旦源对象跟目的对象时同一类型,或者是目的类的扩展类,就可以从基类句柄tr中拷贝扩展对象的地址给扩展对象的句柄bad2了。
使用$cast拷贝句柄
bad = new(); //构建BadTr扩展对象
tr = bad; //基类句柄指向扩展对象
$cast(bad2,tr); //如果成功,bad2就指向tr所引用的对象
/*将$cast作为一个任务来使用的时候,SV会在运行时检查源对象类型,如果跟目的对象类型不匹配则会给出一个错误报告。
将$cast作为函数使用时,SV仍然做类型检查,但是在失配时不再输出错误信息。
如果类型不兼容,$cast函数返回0,兼容则返回非零值。
*/
二、虚方法
当需要决定调用哪个虚方法的时候,SV根据对象的类型,而非句柄的类型来决定调用什么方法。
Transaction tr;
BadTr bad;
initial begin
tr = new();
tr.calc_crc(); //调用Transaction::calc_crc()
bad = new();
bad.calc_crc(); //调用BadTr::calc_crc()
tr = bad; //基类句柄指向扩展对象
tr.calc_crc(); //调用BadTr::calc_crc()
注意的是,如果没有对calc_crc使用virtual修饰符,SV会根据句柄的类型,而不是对象的类型。
三、签名
一旦定义了一个虚拟的子程序,所有带有该虚拟子程序的扩展类就必须使用相同的“签名”,例如相同类型和个数的参数。
在扩展类的虚拟子程序中不能增加或者删除参数,否则多态就不再适用了,代码必须能够调用一个虚方法,并且保证该方法在派生类中具有相同的接口。