目录
一、面向对象编程(OOP)概述
OOP(Object Oriendted Programming),即面向对象编程。OOP使用户能够创建复杂的数据类型,并且将它们跟使用这些数据类型的程序紧密结合在一起。
在SV中,类可以定义在program、module、packge中,或者这些块之外的任何地方,并且类可以在模块和程序中使用。当项目中,单独类文件太多时,可以使用包(package)将一组相关的类和类型定义捆绑在一起。
面向对象编程OOP,即将一切事物和具体问题进行抽象概括,并将其看作是一类对象。数据抽象就是对现实世界的一种抽象,而类(class)是一种用来进行数据抽象的工具,体现的是面向对象程序设计中的抽象特性。类不仅体现抽象的特性,还体现面向对象程序设计中封装的特点。
类的封装,就是将抽象得到的数据和行为相结合,形成一个有机的整体。即,将数据(变量)与数据操作的函数(方法)代码进行有机整合,形成类class,其中数据和函数都是类的成员。类class可以看作是一种特殊的结构体,类中不仅有数据,还可以有函数或任务,即包含成员的变量和方法。
类和结构体的联系和差别有哪些?
联系:类和结构体都可以封装成员变量
差别:类还可以封装成员方法,类需要使用new()来创建对象
通常,类中对于一个问题的描述应该包括两个方面:静态特性的变量抽象(用数据描述)和动态特性的方法抽象(用函数或任务描述)。
二、OOP术语
(1) 类(class):包含成员变量和方法(子程序)的基本构建块,类似于Verilog中的模块(module),将数据和对数据的操作封装在一起。
(2) 对象(object):类的实例化,即类例化后的实例(实体)。
(3) 句柄 (handle):指向对象的指针,就像一个对象的地址。
(4) 原型 (prototype):程序的(头)声明部分,包含程序名,返回类型和参数列表。程序体则是包含了执行代码。
(5)方法 (method):操作变量的程序代码,如任务task和函数function
。
(6)属性(property):类中存储数据的变量,类似verilog中的reg和wire类型的信号。
一个很好的比喻,将类看作一个房子的设计蓝图(blueprint),描述了房子的结构,图纸不能住人,需要建造一座实际的房子,一个对象就是一个实际的房子,根据设计图可以建造房子的各个部分,像类也可以创建很多的对象,房子的地址就像一个句柄,它唯一标志了你的房子。房子里的带有开关的灯(开或者关),像是类中的变量用来保存数值,子程序用来控制这些数值。
三、创建新对象
类在定义时,需要定义构建函数new(),如果未定义系统会自动帮助定义一个空的构建函数(没有形式参数,函数体亦为空),类本身并不占用内存空间,而对象实例会占用内存空间。
- 如果一个对象没有句柄指向时,其内存空间将被释放;
- 可通过将句柄设置为null,手动释放内存空间;
对象在创建时,需要先声明再例化,同时进行亦可。
一般用类需要三个步骤 :
定义class——声明一个handle——new()函数开辟空间创建对象
class Packet; // 1.自定义创建类class
integer command; //属性——数据变量
function new () ; //方法——函数,或称对数据的操作
command =IDL.E;
endfunction
endclass
Packet p; //2.句柄声明
p = new ; //3. 创建对象,分配内存空间
initial begin
$display("*****handle p is :%h",p); //打印基地址
end
声明句柄p时,它被初始化为null.然后用new()函数为Packet创建对象并初始化变量为默认值(二值为0,四值为X),并返回保存对象的地址。
new()与new[]异同
:
1.都申请内存并初始化变量
2.new( )用于创建一个对象,可以使用参数设置对象的数值
3.new[ ]用于建立一个含有多个元素的数组,只需要使用一个数值来设置数组的大小
四、静态成员(变量/方法)
·类的成员(变量/方法)默认都是动态(automatic)生命周期,·如果多个对象为了共享一个成员(变量/方法),那么可以为其添加关键字static。
·同一个类多个对象因此可以共享同一个成员变量或者方法。
class Packet ;
static integer fileID = $fopen ( "data" , "r”);
...
endclass
Packet p;
c = $fgetc( p.fileID ) ; // OR Packet: : fileID
class id;
static int current = 0 ; //static声明——静态数据成员(静态变量)
static function int next_id() ; //定义静态函数成员
next_id = ++current; // oK to access static variable 静态函数调用静态变量
endfunction
endclass
transaction::current; //不通过句柄实现静态变量的调用
- 静态数据成员用于存储可变数据,可用于记录一个类所创建的实例对象的数量;
- 静态(函数)方法无法访问非静态成员(变量/方法),只能处理静态数据成员,否则会发生编译错误。且可以不通过句柄实现静态函数成员的调用(用域操作符 ::);
五、this指针
- this是用来明确索引当前所在对象的成员(变量/参数/方法)。
- this只可以用来在类的非静态成员、约束和覆盖组中使用。
- this的使用可以明确所指向变量的作用域。
class Demo ;
integer x;
function new (integer x) ;
this.x = x ;
endfunction
endclass
六、在类中声明另一个类句柄
常见的类的成员包括四个主要部分:
- 数据变量;
- 对数据的操作(方法与任务);
- 其它类的句柄;
- 约束语句块;
在对外部的类创建对象时,内部声明的类也会同时创建对象,默认含有内部类的new函数;在创建外部类对象时,会对类中的成员赋值,在这个过程中,内部另一个类的句柄也会同时被赋值,从而有了一个具体的基地址,即创建了内部类的对象。
七、对象句柄的赋值与拷贝、数据的隐藏和封装
Packet p1 ;
Packet p2 ;
p1 = new ;
p2 = new p1 ; //浅拷贝
p2.copy(p1); //深拷贝,自定义copy函数
·如果将p1赋值给另外一个变量p2,那么依然只有一个对象,只是指向这个对象的句柄有p1和p2.
·以下这种方式表示p1和p2代表两个不同的对象。在创建p2对象时,将从p1拷贝其成员变量例如integer、string和句柄等,该种拷贝方式称为浅拷贝(shallow copy) 。
1)、 浅拷贝:只拷贝对象中的数据变量,浅拷贝前后的数据变量使用不同的内存空间;而对于对象中的数据操作(任务和函数)和其中定义的其它类的句柄,采取类似“引用操作”的方式,浅拷贝前后共用同一内存空间(浅拷贝不会复制嵌套的对象,只是复制了句柄)。
2)、 深拷贝:对于对象中的所有成员统一分配新的内存空间,区别于浅拷贝。
数据的隐藏和封装
- 类的成员(变量/方法)默认情况下,即是公共属性的。这表示对于类自身和外部均可以访问该成员。
- 对于商业开发,类的提供方会限制一些类成员的外部访问权限,继而隐藏类成员的更多细节。
- ·这种方式也使得类的外部访问接口更为精简减轻了类的维护工作量,也使得类在修改时便于与旧版本保持兼容。
- 数据隐藏的方式使得类的测试和维护都变得更为简单。
参考链接:https://blog.csdn.net/weixin_46022434/article/details/105431180