目录
类是将相同个体抽象出来的描述方式,具有相同属性和功能的对象属于同一类,类的定义核心是属性声明和方法定义,是数据和方法的自洽体,可以保存和处理数据。
面向对象编程(object oriented programming)三要素:封装(encapsulations)继承(extends)多态(polymorphic)
1、oop概念要素
class类:基本模块包含成员变量和方法。类比于“硬件盒子”module,class是软件盒子;
Object:类的实例,类比于“硬件”的例化;
Handle句柄(指针):sv中对象索引通过句柄索引对象的变量和方法;
property(变量):默认为动态变量;
methon(方法):task、function,不能有initial、always。
2、创建对象
Transaction tr; //声明句柄,tr=null;
tr=new() //创建对象,句柄tr指向对象;
注意:构建函数new()是系统预定义函数,会隐式返回指针。
3、类的静态变量与方法
静态变量
在class中声明的变量默认类型为动态变量,可使用关键字static声明class中的变量,声明为静态变量后,会在编译阶段就产生直达仿真结束。
注意:1、此时可以在class未创建对象的情况下引用,引用格式为class::var ;2、在class创建对象的情况下引用,引用格式为object.var(object是所建对象句柄名称);3、无论例化多少对象,只可以共享一个同名静态变量。
静态方法
在class中声明的方法默认类型为动态方法,可使用关键字static修改其类型为静态方法。
注意:静态方法可以声明并使用动态变量,但是不能使用类中的动态成员变量,因为class未建立对象时,不存在该动态成员变量。
5、类、模块、结构体对比
class | struct |
声明之后需要构造才会构建对象 | 声明时已开辟内存 |
可以声明方法task、function,包含成员及对成员操作 | 只能包含数据成员 |
class | module |
任何时候开辟空间 | 初始建立空间 |
动态方式、可选择protecte、local | 过程块、变量是静态,变量方法是开放的(public) |
6、使用位置注意点
可以定义类的位置module、interface、program、package
类中可以再次声明类成员,如类A中包含类B的句柄
this.X 调用成员是当前类的成员,而非同名的局部变量或形式参数,当this.name在当前类中找不到name成员时,会去父类索引,还是找不到就去外面索引。
4、类的封装
类作为载体,也具备天生的闭合属性,即将其属性和方法封装在内部;
关键词public :都可以使用。
关键词protected:父类对象和其子类对象内部使用,外部无法访问。
关键词local :只有父类对象内部可使用成员,外部无法访问。如父类内部使用关键词local clock;Tr为父类对象句柄,外部无法使用Tr.clock。
7、类的继承
继承:通过extends子类继承父类的属性、方法。
子类继承父类的成员与方法,且子类内部不用在例化父类对象的情况下,直接使用(加关键词this、supur)父类的成员和方法。function new()中先super.new()才可以继承父类new()的属性。
形式:class kid extends father;
super.方法/变量:一定不在子类中,而是去父类中找。
this.方法/变量 :先在子类中找,找不到再去父类中找
- 注意:子类在定义new函数时,应该首先调用父类的new函数即super.new()。如果父类new函数没有参数,子类也可以省略该调用,系统将会自动添加super.new()。没有调用的后果是父类函数中的成员变量不会被开辟空间。
- 父类有llp方法,子类也设置类llp方法,两者仅是同名的方法,无关联。
- 父类有llp方法,子类也设置类llp方法,并在子类llp方法中第一行写super.llp()、则继承父类方法,就相当于把父类方法代码平铺到子类方法中,其实子类和父类设置的方法名字“llp”可以不同,但是如果父类方法需要传入参数,则子类方法传入参数需要一致,不然子类中调用 父类方法所需的参数 会出现找不到参数的情况。
- 区别于继承,多态是:通过虚方法进行动态绑定,达到句柄根据指向对象调用对应方法的效果。
8、类的多态
类的多态:主要是父类方法会被覆盖或继承就应该声明为虚方法。
- 两种多态方法声明情况:
- 父类方法(task或function都可以)virtual A,子类方法virtual A;
- 父类方法virtual A,子类方法 A。
- 当父类句柄指向子类对象时,如果父与子有同名函数且加了virtual(或只是父类加viretual),则父类句柄会调用子类中的方法。(更深入来讲是依然调用父类方法,但是父类方法加了virtual,方法在子类中被重写了)
- 但是注意:1、方法加virtual,方法名字一样;2、且有一致的参数和返回值。
- 与继承不同的是没有在子类方法中加super.moth() ;
- 益处是:父类句柄指向子类对象时,父类句柄可直接调用子类方法。
- 动态绑定,根据指向对象调用方法,结合之前实验,父类句柄test[xxx]=t1(子类);后,test[xxx].run()是父类的run(),但父类中的virtual task do_reg()等都被子类更新了,且不是方法继承的方式,没有super.do_reg()。
9、$cast的使用
- 对于变量:$cast(A,B)首先B的类型和值都是不变的,A的值被赋值为B的值(这个值的类型是A的类型)。比如:A=5.0、B=6,$cast(A,B)后A=6.0,B还是6。
- 对于句柄:$cast(Tc,Tf)Tc句柄是Tf对象的子类句柄,成功转化的前提是Tf指向的对象是子类对象(既父类句柄指向子类对象,可通过Tf=Tc操作实现),$cast的目的是:让Tc指向Tf所指向的对象(因为父类句柄Tf虽然指向子类对象,但是不能对子类对象中属于子类部分的成员操作,所以才利用cast让一个子类句柄Tc指向Tf所指向的子类对象),此时便可以通过操作Tc句柄改变Tf指向对象中的内容,也就是实现了可以修改Tf指向对象中所有成员的功能。
- 需要注意的是(很重要),一些函数在句柄传递进来,返回出去的时候,可能默认进行了隐形转化。比如:传进来的子类句柄,隐形转化为了指向子类对象的父类句柄。返回出去的默认为父类句柄。