问题一:动态类型转换和静态类型转换的区别?
$cast
:基本语法$case(A,B)
实际上是A=B;A表示目的端,B表示源端。(downcasting)类型向下转换
- $cast 动态类型转换,转换失败会报错。
- `静态类型转换,转换时报不报错
问题二:$cast是function还是task?
据语境,仿真器会自动选择执行task或是function,task在不需要返回值时执行,而function在需要返回值的语境下执行。将cast作为任务还是函数调用确定了无效赋值是如何处理的。
问题三:什么时候需要$cast?
我们通过下面的一个简单的例子来进行说明一下。
【多选题】有如下的代码,下面$cast返回值为1的有:(BCD)
class A; endclass;
class B extends A; endclass;
class C extends B; endclass;
A a = new(…);
B b = new(…);
C c = new(…);
A、$cast(b, a)
B、a = c; $cast(b,a)
;
C、$cast(b,c)
D、a = b; $cast(b, a)
解析:,
- 在解析之前,希望大家能够通读一下绿皮书的第八章8.3.1,借用书上的一句话,将一个基类句柄赋值给一个扩展类并不总是非法的,当基类的句柄确实指向一个派生类对象时是允许的。
$cast
子程序会检查句柄所指向的对象类型,而不仅仅检查句柄本身。比如说$cast(B,A)
,会检查句柄A指向的对象是不是句柄B指向的对象的扩展类,或者是同一类型。如果满足的话,你就可以从基类的句柄A中拷贝扩展对象的地址给扩展对象的句柄B了。
看到这里大家应该会有点晕晕的,那我们通过实际的例子来给大家展示一下,cast的实际应用场景。
class bird;
virtual function void hungry();
$display("I am bird,I am hungry");
endfuntion
function void hungry2();
$display("I am bird,I am hungry2");
endfuntion
endclass
class parrot;
virtual function void hungry();
$display("I am parrot,I am hungry");
endfuntion
function void hungry2();
$display("I am parrot,I am hungry2");
endfuntion
endclass
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
I am bird,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
相信大家对这个结果够没有异议,那么接下来我将通过几种场景来深入理解cast。我们假设bird parrot的类不变,改写program的调用。
情景一:基类 = 扩展类
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
A = B;
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
I am parrot,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
- 基类 = 扩展类;A句柄指向parrot的对象
- virtual函数的特性
场景二:扩展类 = 基类
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
B = A;
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
Error-[SV-ICA] illegal class assignment
- 扩展类 = 基类,直接调用会有问题
场景三:cast用作task
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
$cast(B,A);
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
Error-[DCF] Dynamic cast failed
$cast(扩展类,基类)
,上述代码$cast
没有返回值,所以结果是做task用,根据图【cast的task function应用】我们可以知道,如果cast用作task应用的时候失败,则异常结束,直接跳出。
场景四:cast用作function
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
if(!$cast(B,A))begin
$display("B = A; failed");
end
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
B = A;failed
I am bird,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
if(!$cast(扩展类,基类))
,上述代码$cast
有返回值,所以结果是做function用,根据图【cast的task function应用】我们可以知道,如果cast用作function应用的时候失败,返回0,继续运行。
场景五:cast成功转换的应用,B=A,基类的句柄A指向扩展类,扩展类跟B句柄指向的类是同类型的。
program ex;
bird A;
parrot B;
initial begin
A = new();
B = new();
A = B;
if(!$cast(B,A))begin
$display("B = A; failed");
end
else begin
$display("B = A; OK !!!!");
end
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
B = A;OK !!!!
I am parrot,I am hungry
I am bird,I am hungry2
I am parrot,I am hungry
I am parrot,I am hungry2
- B=A,基类的句柄A指向扩展类,扩展类跟B句柄指向的类是同类型的。(参考书上的那句话,这里通过例子深入理解一下)
场景六:cast成功转换的应用,B=A,基类的句柄A指向扩展类,扩展类是B句柄指向的类的扩展类。
class dog extends parrot;
virtual function void hungry();
$display("I am dog,I am hungry");
endfuntion
function void hungry2();
$display("I am dog,I am hungry2");
endfuntion
endclass
program ex;
bird A;
parrot B;
dog C;
initial begin
A = new();
B = new();
C = new();
A = C;
if(!$cast(B,A))begin
$display("B = A; failed");
end
else begin
$display("B = A; OK !!!!");
end
A.hungry();
A.hungry2();
B.hungry();
B.hungry2();
end
endprogram
运行结果:
B = A;OK !!!!
I am dog,I am hungry
I am bird,I am hungry2
I am dog,I am hungry
I am parrot,I am hungry2
- B=A,基类的句柄A指向扩展类,扩展类是B句柄指向的类的扩展类。(参考书上的那句话,这里通过例子深入理解一下)
相信通过上述的六种场景,大家对cast应该有了一定的了解,那么对我们最开始的那道题,大家应该都能理解了吧。