继承
在验证的过程中,经常会有新的测试用例被添加进来,而且需要对原有的验证平台进行改进,特殊的测试用例经常会要求验证平台添加特定的功能。在过程化编程语言中,这要求修改原来的代码并且有可能修改原有的数据结构,这个过程可能会在原有的验证环境中引入意外的错误。面向对象编程语言提供了一个高层次的重用功能:通过对已有的基类引申或者扩展,生成新的子类。
所谓继承,就是指从父类扩展创建出的新的派生类(子类)继承了父类中的成员,属性和方法。
在继承的过程中,存在如下的一些基本规则。
1)子类继承父类的所有数据成员和方法。
2)子类可以添加新的数据成员或者方法。
3)子类可以重写基类中的数据成员和方法,也就是重写。
4)如果一个方法被子类重写,其必须保持和基类的原定义有一致的参数。
5)子类可以通过super操作符引用父类中的方法和成员。
6)被声明为 local的数据成员或方法只能对自身可见,而对于外部和子类不可见;
class packet;
integer status;
task rst();
status = 0;
endtask
endclass
class Deriverpacket extends packet;
integer a, b, c;
task showstattus();
$display(status);
endtask
endclass
如上:子类Deriverpacket继承了packet中所以的数据成员和方法,并可以添加新的数据成员或者方法。
类的重写实例:
class packet;
int status = 4;
function int chkstat(int s);
return(status == s);
endfunction
endclass
class Derivedpacket extends packet;
int status = 15;
function void chkstat(int s);
$display(status);
endfunction
endclass
在扩展的过程中,子类 Derivedpacket重写了父类中原有的成员和方法。其中,将 status的初值设置为 15,而 chkstat改为打印信息而不是返回数值。
多态
对于子类对象来说,当子类对象调用一个重写于父类的方法时,即子类中与父类同名的的方法,此时父类中的方法会被调用,而不是重写的那一个。因为默认情况下,子类中重写的方法对父类是不可见的。
虚方法
假如我们希望重写的方法能够被父类看得到,该如何处理呢?也就是说,假如我们希望build_packet能够调用子类中重写的build_payld,我们可以在类中的方法被定义的时候通过添加virtual关键字来声明一个虚方法,虚方法是一个基本的多态性结构。虚方法为具体的实现提供了一个原型,也就是说派生类中,重写该方法的时候必须采用一致的参数和返回值。
class basepacket;
int A=1;
int A=2;
function void printA;
$display("Basepacket::A is % d", A);
endfunction:printA
virtual function void printB;
$display("Basepacket::B is % d", B);
endfunction:printB
endclass:Basepacket
class My_packet extends Basepacket;
int A = 3 ;
int B =4;
function void printA;
$display("My_packet::A is % d", A);
endfunction : printA
virtual function void printB;
$display("My_packet::B is % d", B);
endfunction:printB
endclass :My_packet
...
Basepacket p1 = new;
My_packet p2 = new;
intial begin
p1.printA; //打印Basepacket::A is 1
p1.printB; //打印Basepacket::B is 2
p1=p2; //p1指向My_packet 对象
p1.printA; //打印Basepacket::A is 1
p1.printB; //打印My_packet::B is 4
p2.printA; //打印My_packet::A is 3
p2.printB; //打印My_packet::B is 4
end
在 p1指向 p2后,当 p1.printA 被调用的时候,程序会调用访问内存中类对象 p2中 p1 的部分,而此时发现printA是一个普通方法,为此直接调用并结束访问
p1.printB被调用的时候,程序同样找到类对象p2中p1的部分,此时发现 printB是个虚方法,这时其会咨询系统,查看整个 p2在定义的时候是否重写了该方法,系统发现在p2中(除了p1外)确实重写了该方法,为此,程序会直接调用 p2重写的实现;为此输出会是 My_packet::B is 4。
封装可以隐藏实现细节,使得代码模块化,继承可以扩展已存在的代码模块,它们的目的都是为了代码重用,而多态则是为了实现另外一个目的:接口重用。多态类提供了相同的操作接口,但能适应于不同的应用要求。当基于父类所设计的程序在应用的时候需要适应子类操作变化时,就需要使用虚方法通知编译器这种可能的变化,使编译器为虚方法调用生成特别代码,以便运行时对虚方法调用采用动态绑定。
实现多态步骤
1)在父类中定义虚方法。如 Basepacket类中的虚方法 printB。
2)在子类中重写父类中的虚方法。如My_packet中对printB的重写。
3)申明父类对象的变量(如p1),该变量既可以指向父类对象 (如p1自身),也可以指向子类对象(如p2)。当变量指向父类对象时,调用的是父类方法;当变量指向子类对象时,调用的是子类同名方法。为此,当父类的对象指向不同的子类对象的时候,虚方法(如printB)可以表现出不同的实现方法,而它们都可以通过统一的父类对象实现访问。