一、类的继承
1.概述
- 类的三要素之一除了“封装”,还有一个就是继承
- 类的继承概念与之前学过的C++和将Java几乎一样,关键字用的是extends
在一个验证环境中,BadTr是Transaction的子类,Transaction是BadTr的父类。BadTr重新定义了汉书calc_crc()和display(),在其内部,通过super来引用父类的同名函数。
2.验证环境中的案例
在另外一个验证环境中也有类似的类trans和一个initiator类stm_ini,在test类中通过继承于basic_test的两个子类test_wr和test_rd,分别用来对DUT发起写测试和读测试
basic_test:
class basic_test;
int def = 100;
int fin;
task test(stm_init ini);
$display("basic_test::test()");
endtask
function new(int val);
...
endfunction
endclass
test_wr:
class test_wr extends basic_test;
function new();
super.new(def);
$display("test_wr::new()");
endfunction
task test(stm_ini ini);
super.test(ini);
$display("test_wr::test()");
...
endtask
endclass
test_rd:
class test_rd extends basic_test;
function new();
super.new();
$display("test_rd::new()");
endfunction
task test(stm_ini ini);
super.test(ini);
$display("test_rd::test()");
...
endtask
endclass
- 在上述的类test_wr和test_rd为basic_test的子类(也叫派生类),两个子类继承了父类成员fin也继承了其成员变量和成员方法。
- 子类在调用new函数的时候,应该现调用super.new(),如果没有调用super.new()的话,只是没有执行父类的new()函数初始化变量的部分,但是空间一定会开辟的。
- 从对象创建时的初始化的顺序来看,应该首先调用父类的构造函数,当父类构造函数执行完后,会将子类实例对象中各个成员变量按照定义时的显式的默认值初始化
- 在成员变量默认赋值后,才会最后进入用户定义的new函数中其他的代码
3.成员的覆盖
在父类和子类里,可以定义相同,名称的成员变量和方法(形式参数和返回类型也应该相同),而在引用时,也将按照句柄类型来确定作用域。
test_wr:
class test_wr extends basic_test;
int def = 200;
function new();
super.new(def);
$display("test_wr::new");
$display("test_wr::super.def = %0d", super.def);
$display("test_wr::this.def = %0d", this.def);
endfunction
...
endclass
tb:
module tb;
...
basic_test t;
test_wr wr;
initial begin
wr = new();
t = wr;
$display("wr.def = %0d", wr.def);
$display("t.def = %0d", t.def);
end
...
- 问:在以上代码中,wr.def和t.def的值分别是多少?
- A.100,100 B.100,200 C.200,200 D.200,100
- 答案是D,虽然子类句柄和父类句柄指向的是同一个对象,父类句柄只能访问属于其类型部分的数据。就如同下图所是:
- 父类句柄不能赋给子类句柄,但是可以用$cast(wr, t);来转换。(可以理解成=,把右转左)