• 类的继承是从继承成员变量和成员方法两个方面。
• 从以下例码中可以看到test_wr类和test_rd类分别继承了basic_test类的成员变量以及成员方法。
• 除了介绍的类的封装和继承,关于类的多态性(polymorphism)也是必须关注的。• 正是由于类的多态性使得用户在设计和实现类时,不需要担心句柄指向的对象类型是父类还是子类,只要通过虚方法就可以实现动态绑定(dynamic binding) , 或者在SV中称之为动态方法查找(dynamic method lookup)。
- class basic_test;
- int fin;
- int def= 100;
- function new();
- $display{"basic_test::new");
- endfunction
- task test();
- $display ("basic_test::test");
- endtask
- endclass
-
- class test_wr extends basic_test;
- int def= 200;
- function new();
- super.new();
- $display("test_wr::new");
- endfunction
- task test();
- super.test();
- $display ("test_wr::test");
- endtask
- endclass
-
- basic_test t;
- test_wr wr;
- initial begin
- wr = new();
- t=wr;
- $display("wr test starts");
- wr.test();
- $display("wr test ends");
- $display("t test starts");
- t. test();
- $display("t test ends");
输出结果:
# wr test starts# basic_test::test
# test_wr::test
# wr test ends
# t test starts
# basic_test::test# t test ends
• 首先 , 在执行wr.test()时,由于wr类型为test_wr, 则索引到的test()应该为test_wr类的方法test。
• 同时 , 由于在test_wr::test中显式调用了super.test(), 则会先执行basic_test::test, 然后再执行test_wr::test中其余的代码。
• 这里值得注意的是,默认清况下,子类覆盖(override)的方法并不会继承父类同名的方法,而只有通过super.method() 的方式显式执行,才会达到继承父类方法的效果,初学SV的用户容易在这里混淆方法覆盖和类继承的概念。
• 当wr对象的句柄传递给t后 , 由于t本身是basic_test类, 所以, 在执行t.test时, t只会搜寻basic test::test方法。

• 从输出结果看到,t.test并没有执行test_wr::test,而是执行了basic_test::test。
• 这种执行结果使得我们不得不小心句柄传递时的类型, 而这种限制又跟类的多态性支持是违背的。
• 因为父类的句柄可以指向子类对象, 但如果无法通过父类句柄调用子类方法的话, 那么这种句柄的传递也就失去了多半的意义。
• 在实际编码过程中, 我们需要父类句柄在调用方法时, 可以在运行时确定自身指向对象的类型, 进而再调用正确的方法。• 我们将已经在编译阶段就可以确定下来调用方法所处作用域的方式称之为静态绑定(static binding) , 而与之相对的是动态绑定。
• 动态绑定指的是, 在调用方法时, 会在运行时来确定句柄指向对象的类型, 再动态指向应该调用的方法。
• 为了实现动态绑定, 我们将basic_test::test定义为虚方法。
只需要给父类的方法前添加virtual,我们重复运行之前的测试代码,可以看到运行结果变为:
# wr test starts
# basic_test::test
# test_wr::test
# wr test ends
# t test starts
# basic_test::test# test_wr::test
# t test ends
由于声明了basic_test::test为虚方法,系统在执行t.test时, 会检查t所指向对象的类型为
test_wr类,进而调用test_wr: :test。
于是,输出结果与调用wr.test一致。我们就可以通过虚方法的使用来实现类成员方法调用时的动态查 找, 用户无需担心使用的是父类 句柄还是子类句柄, 因为最终都会实现动态方法查找,执行正确的方法。

• 在为父类定义方法时,如果该方法日后可能会被覆盖或者继承, 那么应该声明为虚方法。
• 虚方法如果要定义,应该尽量定义在底层父类中。这是因为如果virtual是声明在类继承关系的中间层类中,那么只有从该中间类到其子类的调用链中会遵循动态查找,而最底层类到该中间类的方法调用仍然会遵循静态查找。• 虚方法通过virtual声明,只需要声明一次即可。例如上面代码中只需要将basic_test::test声明为virtual,而其子类则无需再次声明,当然再次声明来表明该方法的特性也是可以的。
• 虚方法的继承也需要遵循相同的参数和返回类型,否则子类定义的方法须归为同名不同参的其它方法。