OOP的概念
面向对象的编程语言有三大核心特征:封装、继承和多态。类是抽象出事物的一个共性。
- 首先"男人"和"女人"都是人,那么"人"就是一个人类,男人类和女人类分别是继承于这个人类。
- 男人和女人都要吃饭,都具有年龄和姓名,所以人类中就有两个成员变量年龄和姓名,有一个成员方法吃饭这个动作,把这些属性和行为封装在一个类中,就是封装。
- 当男人类创建一个男人对象时,这个男人天生就具有年龄和姓名,也会吃饭。这就是继承。我们不需要自己在男人类中给男人这个对象去定义这些,他就天生具有人类的特质。
- 但是我们发现,男人吃饭要吃两大碗,女人只吃一碗。这时候男人类和女人类中就要修改这个吃饭方法,就可以通过虚方法(virtual)实现男人和女人吃饭时饭量的不同,这就是多态。多态也就是众多类中抽象出共性的一个方法,它在不同的子类中会表现出不一样的行为。
注:虚方法(virtual)可以看:虚方法
1. 创建对象
首先,SV 中的class例化和Verilog 中的例化的区别:Verilogl例化是静态的,即编译链接时就已经完成,而SV class例化是动态的,可以在仿真0时刻和其他任意时刻例化。
// 声明类
class Transaction;
//构造函数
function new();//创建对象时,可以通过自定义构建函数来完成变量的初始化和其他初始操作
...//构建new()时,不需要返回值,函数会隐式地返回例化后的对象指针
endfunction
endclass:Transaction
// 声明句柄
Transaction tr,tr1,tr2;//此时指针悬空,为null值,没有指向任何对象
Transaction tr= new();//申明句柄+创建对象,为对象分配一个地址
// 创建对象
tr1 = new(); // 将句柄赋予给tr1
tr2=tr1;//将tr1的值赋给tr2,即tr1 、tr2指向同一个对象
tr2 = new();//将句柄赋予给tr2
注意:类中定义的变量不能是wire和reg,也不能出现initial和always;即硬件世界的部分不能在软件世界中定义。
调用new( ) 时,系统的步骤:
-
系统开辟空间;
-
将开辟的空间分配给变量,进入new()函数对变量初始化.
-
退出new( )时,将当前对象的句柄返回
注意:new()函数创建对象时,会为对象分配地址,将类中变量初始化(二值变量为0,四值变量为x)。
2. 对象的销毁
SV采取自动回收空间的处理方式。当一个对象,在整个程序中没有任何一个地方再“需要”(没有句柄指向它)它时,便会被“销毁”,即回收其空间。
3. 类的成员
在class中声明的变量默认是动态变量(这跟module恰恰相反),但可以用static来声明静态变量(可以看:静态变量和静态方法)。
注:在类里面声明一个接口的指针,必须要加virtual。
class TB;
local virtual interface_test it;//声明一个接口指针
endclass
3.1 成员的访问权限
为了提高类封装后的安全性,即类中的有些成员方法和变量不希望被外部或子类访问,就可以通过关键词修饰,设置变量和方法的访问权限:
- 默认情况是子类和外部都可以访问;
- protected只有该类和子类可以访问,外部不可访问
- local只有该类可以访问,子类和外部都不可访问
3.2 this 和 super的区别
有的时候我们会使用this 和 super调用成员变量和方法,this 和 super的区别在于:
- this 会先在当前作用域中查找,如果当前作用中没有,则会去上一级作用域中查找,知道找到该变量为止;
- super首先会先在该类的父类中查找。
3.2 类与的差异
结构体(struct)可以自定义一个类型,类也是一种类型,那类与结构体的异同在于:
- 二者本身都可以定义数据成员;
- 类在变量声明后,需要构建才会创建对象实体;而struct在变量声明时就已经开辟内存;
- 类可以声明方法和任务,而结构体不能;
- 从根本上看,struct是一种数据结构,而class则包含了数据成员以及针对成员的操作方法
4. 类的继承
如果父类的构造函数有参数,那么子类必须有一个构造函数,而且必须在其构造函数的第一行调用父类的构造函数(super.new( ))。
class Father
string name = "father";;
function new(string name);
this.name = name;
endfunction
endclass
class Son extends Father;
int son_age = 5;
function new(string name);
super.new(name);
name = "son";
son_age = 15;
endfunction
endclass
对象创建时初始化的顺序:
-
子类的实例对象在初始化之前会先调用父类的构造函数;
-
当父类构造函数完成时,会将子类实例对象中各个成员变量按照他们定义时显式的默认值初始化;
-
在成员变量默认值赋予后,才会最后进入用户定义的new函数中执行剩余的初始化代码。