(六)SV的类、类的成员操作

一、类

1、具有(相同或者类似)属性和行为的一系列对象的集合。关键字:class、endclass

2、类的特征:

  • 封装:将对象的属性和行为封装起来,对用户隐藏类实现的细节。
  • 继承:一个类获取另外一个类的属性和行为的方式。
  • 多态:同一个行为具有多个不同表现形式或形态的能力,当同一操作作用于不同对象,能有不同的解释从而产生不同的结果

3、验证中,为什么要有类的存在?

①激励生成器(stimulus generator):生成激励内容

②驱动器(driver):将激励以时序形式发送至DUT

③监测器(monitor):监测信号并记录数据

④比较器(checker):比较数据

同一验证环境中,验证环境的不同组件其功能和所需要处理的数据内容是不相同的,不同环境的同一类型的组件其所具备的功能和数据内容是相似的(这提供了继承的可能性,使新的项目组件可以继承旧的项目组件)。

二、对象

对象:就是对类的实例化,SV采用oop编程(Object Oriented Programming)

类是成员变量和成员方法的载体,类的成员访问类型:

  • public:如果没有指明访问类型,默认是public,子类和外部均可以访问成员
  • protected:只有该类或者子类可以访问成员,外部不可访问
  • local:只有该类可以访问成员,子类和外部均无法访问

举例说明类和对象里的一些问题:

class Transaction;
	bit [31:0] addr,crc,data;
function void display();
	$write("TR:addr=%0d,crc=%0d,data=%0d",addr,crc,data);//write打印没有换行
	$display();//打印换行
  endfunction
endclass

class PCI_Tran;
	bit [31:0] addr,data;

function new(logic [31:0] addr1=3,data1=5);//定义的带参数的且有默认值的new函数
    addr = addr1;
    data = data1;
endfunction

function void display();
		$display("PCI:addr=%0d,data=%0d",addr,data);
endfunction
endclass

Transaction t;//声明句柄,  此时被初始化为null
PCI_Tran pc;
module test15();
	initial begin
		t = new();//分配存储空间
		t.display();
		pc = new(,8);//注意逗号对应前后的形参
		pc.display();
	end
endmodule


打印结果:
TR:addr=0,crc=0,data=0 
PCI:addr=3,data=8

说明:(重点理解)

句柄可以理解为C语言中的指针

1、在声明句柄t,pc的时候,该句柄被初始化为特殊值null。接下来,你调用new()函数来创建Transaction,PCI_Tran对象,且new函数为创建的对象分配空间,将变量初始化为默认值(二值变量为0,四值变量为X),并返回保存对象的地址给对应的句柄。对于每一个类来讲,System Verilog创建一个默认的new函数来分配并初始化对象。

2、new函数:构造函数,SV中类有一个自带的new函数,若没有自己定义,系统将自动调用自带的new函数,new函数主要就是起初始化类的成员属性和分配地址空间的作用,自己定义的new函数可以是不带参数的,也可以是带参数的,如上例,New函数没有返回值,因为构造函数总是返回一个指向该类的对象的句柄,其类型就是类本身

二、this指针

在面向对象语言中,this表示对当前对象的一个引用,可以理解为指向对象本身的一个指针,并且常作为类中方法的隐含形参,通过该形参可以访问对象内部的属性和方法,因此,一般方法对于编译器来说,原型结构如下:

[return_type] func_name(class_type const this,other_args)

  • 其中 return_type为方法返回类型
  • class_type当前方法所属的类
  • other_args当前方法其他形参

说明:

  1. 当一个对象创建时,不同对象变量大小有很大的可能是不同的,所以我们定义的时候编译器就为其开辟了空间,但是他们调用各自函数时调用的都是同一个函数,那么也就没有必要再为同一个类的每个对象的函数单独开辟空间,所以此时的函数是保存在公共代码区的,即所有方法放在同一空间,类内的成员变量和成员方法分开存储,当对象调用方法时候是把对象的地址给this指针,通过this指针去调用方法的,因为类中的方法有一个隐含的this形参,this指针在调用方法时就存在,当方法调用结束时其生命周期也就结束了,this指针就不再指向对应方法的区域了,在方法中不必显式的使用this 指针来访问该方法所属对象的属性和其他方法,此时对于这些没有采用this前缀进行访问的属性和方法都被假定为通过this实现了引用。
  2. 非静态成员变量,属于类对象,占用类对象空间
  3. 非静态成员函数 不属于类对象,不占用类对象空间
  4. 静态成员函数,静态成员变量都不属于类对象,都是单独的存储空间

 三、静态变量

1、静态变量就是在函数调用前后的值不会被销毁的变量,在内存中单独存储

class Transaction;
    static int count=0;
    int id;
    
    function new();
        id=count++;//id首先使用count=0的值,再++
    endfunction
endclass
 
program example;
    Transaction t1,t2;
    initial begin
        t1=new;//第一个实例,id=0,count=1
        t2=new;//第二个实例,id=1,count=2
    end
endprogram

域作用符“::

  • 全局作用域符(::name):局部变量与全局变量命名相同都要调用冲突时,表示变量前加作用域为全局命名空间。
  • 类作用域符(class::name):用于表示指定name变量是属于哪个类的,如:Transaction::count
  • 命名空间作用域符(namespace::name):用于表示指定类型的作用域范围是具体某个命名空间
  • 类外声明函数,复制该方法的第一行,包括方法名和参数,然后在开始处添加关键词extern。然后将整个方法移至类定义的后面,并在方法名前加上类名和两个冒号(::作用域操作符)。
class Transaction;
  bit [ 31:0]addr ,crc, data [8];
  extern function void display();
endclass
function void Transaction::display () ;
  $display ("@% 0t : Transaction addr=%h, crc=%h",
  $time , addr , crc);
  $write("\tdata [0-7]=");
  foreach (data[i])$write (data [ i] );
  $dispiay();
endfunction

四、句柄传递、浅复制、深复制

1、句柄传递

Transaction t1,t2; // 声明句柄
t1 = new();        // 创建对象并将其指针赋予t1
t2 = new();        // 创建对象并将其指针赋予t2
t1 = t2;//句柄传递
// 将t2的值赋予t1,t1和t2指向同一对象,同一片地址区域
// t1之前指向的对象被释放
t2 = null;
// 将t2赋值为‘空’即不指向任何对象,
// 此时指针‘悬空’,悬空的指针很‘危险’

2、浅复制

1、方法:tr2 = new tr1;浅复制复制对象的所有属性,在new复制一个对象时不会调用自己写的new函数,所以也不会对更深层次对象复制,即复制不包括属性成员中句柄指向的对象,示例:

class packet;
	bit [7:0] payload;
endclass

class transaction;
	bit [7:0]  addr;
	bit [7:0]  data;
	packet     pkt;
	
function new();
	pkt = new();
endfunction

function void assig(bit [7:0]  addr0,bit [7:0]  data0);

	this.addr = addr0;
	this.data = data0;
	
endfunction

endclass

program test;
	transaction tr1;
	transaction tr2;
initial begin
	tr1 = new();
	tr1.assig(8'd0,8'd1);
	$display("tr1.addr=%d,tr1.data=%d",tr1.addr,tr1.data);
	tr2 = new tr1;
	tr2.assig(8'd2,8'd3);
	$display("tr2.addr=%d,tr2.data=%d",tr2.addr,tr2.data);
	$display("tr1.addr=%d,tr1.data=%d",tr1.addr,tr1.data);
	$display();
	tr1.pkt.payload = 8'd12;
	$display("tr1.pkt.payload=%d",tr1.pkt.payload);
	$display("tr2.pkt.payload=%d",tr2.pkt.payload);
	tr2.pkt.payload = 8'd25;
	$display("tr1.pkt.payload=%d",tr1.pkt.payload);
	$display("tr2.pkt.payload=%d",tr2.pkt.payload);
	
end
endprogram

打印结果:
tr1.addr=  0,tr1.data=  1
tr2.addr=  2,tr2.data=  3
tr1.addr=  0,tr1.data=  1
 
tr1.pkt.payload= 12
tr2.pkt.payload= 12
tr1.pkt.payload= 25
tr2.pkt.payload= 25

 示意图:指明了句柄复制前后的指向

2、深复制

1、深复制就是创建一个新的和原始句柄指向的内容相同的字段,是两个一样大的数据段,复制包括对象的所有属性和更深层次的对象的复制,但需要自己创建copy函数实现,示例

class packet;
bit [7:0] payload;
function packet copy;
	copy = new();
	copy.payload = this.payload;
	return copy;
endfunction
endclass

class transaction;
bit [7:0] addr;
bit [7:0] data;
packet pkt;

function new();
	pkt = new();
endfunction
function transaction copy;
	copy = new();
	copy.addr = this.addr;
	copy.data = this.data;
	copy.pkt  = pkt.copy;
	return copy;
endfunction
endclass

program test;
transaction tr1;
transaction tr2;
initial begin
	tr1 = new();
	tr2 =tr1.copy; 
end
endprogram

 说明:

  • function transaction copy类似于function返回数组的操作,即函数名可以当成变量用

示意图:指明了句柄复制前后的指向

  • 4
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,的封装、继承和多态是面向对象编程的重要概念。下面我将分别解释这三个概念。 1. 封装(Encapsulation): 封装是指将数据和对数据的操作封装在一起,形成一个通过公有(public)和私有(private)成员来控制对数据的访问。公有成员可以被的外部访问,而私有成员只能在内部访问。通过封装,我们可以隐藏数据的具体实现细节,提供对外的接口,实现数据的安全性和灵活性。 2. 继承(Inheritance): 继承是指一个从另一个获得成员和方法的能力。通过继承,我们可以构建的层次结构。子(派生)可以继承父(基)的成员和方法,同时也可以添加自己的成员和方法。继承可以提高代码的复用性,减少重复编写的工作。 3. 多态(Polymorphism): 多态是指同一操作可以在不同的对象上有不同的行为。在面向对象编程中,多态主要通过函数重写(函数覆盖)和函数重载来实现。函数重写是指在派生中重写基的虚函数,使得在调用同名函数时,根据对象的型来调用相应的函数函数重载是指在同一个中,可以有多个同名函数,但参数型或参数个数不同。多态可以提高代码的灵活性和可扩展性。 这些概念是面向对象编程中的基础,对于理解和设计的关系和行为非常重要。在实际的程序开发中,我们经常会使用封装、继承和多态来实现各种功能和实现代码的复用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值