SV 类的虚方法 多态 类型转换
概述
- 类的成员方法可以加修饰词
virtual
(虚方法) - 虚方法是一种基本的多态结构
- 一个虚方法可以覆盖基类的同名方法
- 在父类和子类中声明虚方法,其方法名、参数名、参数方向都应该保持一致
- 在调用虚方法时,它将调用句柄指向对象的方法,而不受句柄类型的影响
class BasePacket;
int A = 1;
int B = 2;
function void printA;
$display("BasePacket::A is %d", A);
endfunction
virtual function void printB;
$display("BasePacket::B is %d", B);
endfunction
endclass
class My_Packet extends BasePacket;
int A = 3;
int B = 4;
function void printA;
$display("My_Packet::A is %d", A);
endfunction
virtual function void printB;
$display("My_Packet::B is %d", B);
endfunction
endclass
module tb;
BasePacket P1 = new();
My_Packet P2 = new();
initial begin
P1.printA; // A is 1
P1.printB; // B is 2
P1 = P2; // 子类句柄赋值给父类,父类句柄指向子类的对象
P1.printA; // A is 1
P1.printB; // B is 4
P2.printA; // A is 3
P2.printB; // B is 4
end
endmodule
父类句柄默认会查找调用父类方法,当子类句柄赋值给父类,父类句柄指向子类的对象后,父类句柄查找方法会扩大到子类里,如果子类里有同名方法,那么就会执行子类的同名方法。故P1.printB()
和P2.printB()
打印结果都是4。
virtual关键字的作用:虽然句柄类型不一样,但是调用函数会以子类的实现优先,即子类如果有同名方法就调用子类里的方法。
变量能不能也声明成virtual:不可以
- 人家都叫虚方法了,都没说虚变量诶
- 父类访问方法的范围可以扩展到子类,但是访问的变量范围只有父类变量范围
- 上述代码子类方法可以不用virtual声明,但是父类一定要声明
- 上述代码,父类不用virtual,子类用virtual,则不行,这样父类对象在查找方法时候,不知道要去子类找,只会在父类范围内查找
一些建议点:
- 类在封装的时候建议不要local、protected
- 类在继承的时候,为了方便以后访问到更多的变量,子类继承父类的时候尽量不要出现同名变量
2022/08/06
再补充一下
- 子类句柄可以直接赋值给父类句柄,这样相当于从大三角形到小三角形,在缩小范围;
- 直接将父类句柄赋值给子类句柄的时候会报错,需要使用
$cast()
系统函数做类型转换; - 父类的句柄如果想要访问子类的方法,使用
vritual
声明虚方法就可以做到。但是如果想用父类句柄直接访问子类变量,这样是不可以的,这样只能将父类句柄转化成子类句柄,再通过子列句柄去访问。
下面对于虚方法的理解,正确的是:
- A:虚方法只需要在父类中声明,不需要在子类定义时添加virtual关键字
- B:虚方法的目的是为了更好的继承,子类在不调用super.method()时不会自动执行父类的方法
- C:使用了虚方法定义的父类句柄在指向子类对象时,可以动态索引到同名的子类变量
- D:与父类虚方法同名的子类方法在继承时可以使用不同类型的参数
没有虚成员这一说法
子类对象可以用super找到父类的变量,但是从父类句柄不能找到子类的对象