1、多态
①多态的意思:
通过父类的句柄可以使用子类的 方法。
②多态的应用场景:
(1) 在不改变原有代码的基础上,想重写原有代码类中的函数;
(2) 子类中重写的方法对父类是不可见的,所以要想子类重写父类的方法能被父类看到,那就需要虚方法。(所以想要不改变原有代码的的话,可以使用多态, 即在子类中写一个同名方法,父类中添加virtual声明,并将父类的句柄指向子类,这样父类句柄就可以调用子类的方法了)
③代码演示
a、 在termial窗口输入 g 1.sv
class bird;
int a = 'h1;
int b = 'h2;
function void display();
$display("bird : a is :%h", a);
endfunction
virtual function void vdisplay();
$display("bird : b is :%h", b);
endfunction
endclass
class sparrow extends bird;
int a = 'h3;
int b = 'h4;
function void display();
$display("sparrow : a is : %h", a);
endfunction
function void vdisplay();
$display("sparrow : b is : %h", b);
endfunction
endclass
module top_tb;
bird bd;
sparrow spw;
initial begin
bd = new ();
spw = new();
$display("--------------------1111111-------------------");
bd.display();
bd.vdisplay();
//如果想要通过父类的句柄访问子类的同名方法,条件有2个。
//(1)父类中的方法用 virtual 声明(只要在最根部的类添加了virtual即可,子类中加不加virtual不影响)
//(2)父类的句柄指向子类
bd = spw;
$display("--------------------2222222-------------------");
bd.display();
bd.vdisplay();
end
endmodule
b、在terminal窗口输入
vcs -R -full64 -sverilog 1.sv 进行编译
c、输出结果
d、分析输出结果:
首先,声明父类bird(鸟类),然后父类里面有两个方法,一个是display,一个是vdisplay(vdisplay有个virtual声明,这是重点);
然后声明一个子类sparrow(麻雀),子类继承父类bird(鸟类),里面有两个方法,一个是display,一个是vdisplay;
然后看到一开始 bd.display()、bd.vdisplay()打印的都是父类中的结果。
然后看到我们把父类的句柄 指向子类的对象,在执行 bd.display()、bd.vdisplay(),可以看到打印的结果是:
bd.display()执行的结果一样,bd.vdisplay()执行的结果不一样,这就是因为vdisplay加了virtual声明,结果是成功通过父类方法调用执
行到了子类里面内容。也满足了应用场景,在不改变原代码的基础上,这就是多态的特性。
2、动态类型转换
应用场景:通过父类的句柄访问子类的 变量.
2.1、代码
父类是bird,子类是sparrow,如下所示
class bird;
int a = 'h1;
int b = 'h2;
function void display();
$display("bird : a is :%h", a);
endfunction
virtual function void vdisplay();
$display("bird : b is :%h", b);
endfunction
endclass
class sparrow extends bird;
int a = 'h3;
int b = 'h4;
function void display();
$display("sparrow : a is : %h", a);
endfunction
function void vdisplay();
$display("sparrow : b is : %h", b);
endfunction
endclass
2.2、向上类型转换
因为,子类sparrow是继承自父类bird的,所以父类里面有的方法,子类都有,所以向上类型转换,不会说找不到;代码如下:
bird bd;
sparrow spw,spw1;
initial begin
spw = new();
bd = spw;//把子类赋值给父类,即将父类句柄指向子类对象.句柄类型并没有发生本质性改变!
bd.display();
bd.vdisplay();
end
向上类型转换,把父类句柄bd指向子类对象spw,不会报错;
2.3、向下类型转换
只有父类的句柄bd指向的是真正子类的对象spw1,然后通过$cast,把子类句柄指定父类的句柄;
initial begin
spw1 = new();
bd = spw1;//子类赋值给父类,没毛病.但是此时bd还不能访问子类的变量,因为bd本质上还是父类句柄,只能访问父类中的东西.
$cast(spw, bd);
end
$cast() 是将父类句柄转换为子类句柄的作用,转换了bd的句柄类型,才真正可以访问子类的成员变量.