紧接上一篇文章SV类型转换,这篇来讲一下虚方法,虚方法是多态的一种表现形式!!!
目录
一、概述
- 类的继承是从继承成员变量和成员方法两个方面
- 从例码中可以看到test_wr类和test_rd类分别继承了basic test类的成员变量以及成员方法
- 除了介绍的类的封装和继承,关于类的多态性(polymorphism) 也是必须关注的。
- 正是由于类的多态性,使得用户在设计和实现类时,不需要担心句柄指向的对象类型是父类还是子类,只要通过虚方法,就可以实现动态绑定(dynamic binding) ,或者在SV中称之为动态方法查找(dynamic method lookup)
二、非虚函数的调用
- 首先,在执行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方法
如下图:
三、虚函数的调用
- 将已经在编译阶段就可以确定下来调用方法所处作用域的方式称之静态绑定(static binding),而与之相对的是动态绑定。
- 动态绑定指的是,在调用方法时,会在运行时来确定句柄指向对象的类型,再动态指向应该调用的方法。
- 为了实现动态绑定,我们将basic test::test定义为虚方法
对上面的例子有一下几点说明:
- 由于声明了basic_test::test为虚方法,系统在执行t.test时,会检查t所指向对象的类型为test_wr类,进而调用test_wr::test
- 于是,输出结果与调用wr.test一致。
- 我们就可以通过虚方法的使用来实现类成员方法调用时的动态查找,用户无需担心使用的是父类句柄还是子类句柄,因为最终都会实现动态方法查找,执行正确的方法。
图文说明:
四、建议
- 在为父类定义方法时,如果该方法日后可能会被覆盖或者继承那么应该声明为虚方法
- 虚方法如果要定义,应该尽量定义在底层父类中。这是因为如果virtual是声明在类继承关系的中间层类中,那么只有从该中间类到其子类的调用链中会遵循动态查找,而最底层类到该中间类的方法调用仍然会遵循静态查找。
- 虚方法通过virtual声明,只需要声明一次即可。例如上面代码中只需要将basic_test::test声明为virtual,而其子类则无需再次声明,当然再次声明来表明该方法的特性也是可以的。
- 虚方法的继承也需要遵循相同的参数和返回类型,否则,子类定义的方法须归为同名不同参的其它方法
这一讲就写到这里,如有疑惑或补充请留言!!!