第四章:面向对象的编程

方法:包括任务或者函数,对对象内的数据进行操作。

对象:包括数据成员和方法。

过程编程语言:数据和方法都是独立的,没有任何联系,一个方法可以对多个数据操作,多个函数可以对同一个数据操作。

面向对象的编程语言:数据和方法被封装到一个对象中,对象和外部的接口通过方法来实现,是一个层次化的实现结构,可以例化复用。

在SV中采用的是面对对象的编程语言,一旦抽象层次被确定,就可以映射到用户自定义类型,这种用户自定义类型就是类(class),类可以将数据和方法封装到一起。

一个对象通过类来定义,类相当于对象的一个模板,定义了数据和方法。对象是类的一个例化和实现。

类:银行卡类

对象:工商卡、交行卡、建行卡...

方法:利息计算、添加交易、余额计算...

类的基本概念

属性(property):类中定义的数据成员

方法(methood):类中定义的函数或任务

句柄(handle):指向对象的指针,即对象地址的入口

用户使用对象包括三个步骤:

1.定义类:class class_name;...endclass

即class 类型名,使用该类型名可以声明类对应的对象。

2.声明对象:class_name object_identifier;

对象的声明可以在module、program class function task等地方声明

Sv除了支持单个对象,还支持以对象数组的方式例化:

class_name object_identifier_arry[];//对象的动态数组,同样需要NEW()例化;

用类型名声明的对象的标识符是例化对象的句柄,也就是例化对象的地址,然而对象的声明并不意味着创建(例化),声明没有实际分配空间,此时句柄无效,值为null

因此还需要构造函数来创建例化对象。

3.通过构造函数new()来创建对象的例化

object_identifier =new();

通过构造函数给对象分配空间后,该对象的标识符,也就是句柄才有效,代表例化对象的入口地址。

因此,一个完整的用户使用对象的创建:

class ether_packet;

print();                 定义一个ether_packet的类,内部包含了print、load

load_frame();            等方法。

Endclass                

module/task/program/function/class    //对象的声明位置很灵活

ether_packet e1_pkt,e2_pkt;    //声明两个对象:e1_pkt和e2_pkt

initial begin

e1_pkt=new(164);       使用构造函数为对象分配空间

e2_pkt=new(88);        分配空间后,其句柄代表了对象入口的地址

e1_packet.print;           

e1_packet.load_frame;       通过.操作符,访问对象中的成员

end

endmodule/task/program/function/class

构造函数

1.如果一个被声明的对象还没被构造,也就是对象的句柄值为null,如果此时句柄被引用,将会产生错误。

可以通过下列代码来检测空句柄:If (object_identifier==null) $stop;

2.对象通过new()函数来初始化,若数据成员没有在new()中初始化,则为默认值。

在构造函数中,数据成员可以被赋初值:

function new()

addr=3;

foreach(data[i])

data[i]=i;

endfunction

也可以通过参数传递对数据成员初始化:

function new(logic[31:0] addr=3,d=5)

this.addr=addr;

foreach(addr[i])

data[i]=5;

endfunction

3.存储空间不再被对象占用时,SV会像java一样,自动收回例化,即自动析构。

module new_struct_example();

`include ether_packet.sv

ether_packet e1_pkt,e2_pkt;  //定义两个以太包类的对象

initial begin

e2_pkt=new(98); //构造函数给e2_pkt这个句柄分配空间,传递98给len变量

e1_pkt=e2_pkt;//并没有给e1_pkt分配空间,而是将句柄e2_pkt赋值给e1_pkt

e1_pkt=new(118);//重新调用构造函数,原来分配的空间自动析构

e1_pkt-new(119);:最终e1_pkt和e2_pkt所指向的空间

e2_pkt=new(200);     

静态属性与方法

1.静态属性

每一个类的例化(对象)都拥有其自身的变量,且一个类的不同对象的成员变量是不共享的,而有时候需要所有对象共享一个变量,这时可以在类的定义中用关键字:static来声明数据成员。例:static int addr=0;

2.静态方法

静态方法对类的所有对象都可以访问;即便类没有被例化,该静态方法也可以在外部被调用;静态方法的声明也是使用static关键字:static function next_id()

注意:静态方法不能访问非静态成员,因此:

class id;

int current=0;

static function int next_id();

next_id=++current;    //出错,因为current为非静态变量,静态方法不能访问,

Endfunction           因此需修改current为:static int current=0;

endclass

注意:静态方法指:类内部方法的生命周期

具有静态生命周期的方法:方法内部的参数和变量的生命周期

class twotasks;

  static task foo();...endtask  //静态方法:具有自动变量生命周期的静态方法

  task statiic bar();...endtask //非静态方法:具有静态变量生命周期的非静态方法

this操作符

关键字this被用来明确的引用当前类的属性方法;对应着一个预定义的对象的句柄,这个句柄可以在对象内部使用,并可以访问内部成员。

注意:关键字this只能在非静态方法中使用。

module this_class_example();

class this_class;

integer x;      //此处x为类的一个属性

 function new(integer x)    //此处X为构造函数new的一个自变量

  this.x=x;        //若没有this,则此处访问的x是构造函数的自变量,为了

 endfunction       访问类的属性,使用了关键字this进行限定。

 endclass

endmodule

对象的赋值与赋值

1.赋值与浅复制

//赋值                         //复制

packet p1;                      packet p1;   

p1=new;                       p1=new;

packet p2;                      packet p2;

p2=p1;                         p2=new p1;

赋值没有产生新的存储空间,因为new仅执行了一次,赋值行为只是把地址入口传入另一个句柄,两个句柄指向的是同一个对象。

复制执行了两次new操作,产生了新的存储空间,且原存储空间所存的属性也被复制了过去,该复制行为属于浅复制,因为它只能复制属性和句柄,其包含的对象并不会被复制。例如:

module shallow_copy();

class A;

   integer j=5;

endclass

class B;

integer i=1

A a=new;  //在B类中例化了A类属性变量a

endclass

Initial begin

B b1=new;

B b2=new b1; //b2是b1的一个再复制,b2中也有变量i和对象a

b1.i=10;

b1.a.j=50;

test=b2.i;   //b2中的i不随b1中的i的改变而改变(b2.i=1)

test=b2.a.j;  //由于复制仅复制了对象a的句柄,并没有为对象a开辟新的存储空间,也就是并没有复制对象a,因此,b2中的对象a和b1中的对象a是同一个对象,b1和b2共享同一个对象,所以b2.a.j=50

 

因此,该复制方式称为浅复制,主要是由于该方式不会复制对象。

2.深度复制

module shallow_copy();

class A;

   integer j=5;

endclass

class B;

integer i=1

A a=new;  

function copy(B in_b);   //在B类中声明copy函数

  this.i=in_b.i; //this关键字限定此处的i为类属性,而不是copy函数自变量

  this.a.j=in_b.a.j;

endfunction

endclass

initial begin

B b1=new;

B b2=new;      分别为两个对象b1和b2开辟存储空间,这样对象b1和b2都

b2.copy(b1);     各自独立的对象a,再利用copy函数,将b1的值赋给b2。

end

endmodule

 

块外声明

将方法定义在类型声明体的外部:

首先:再类内声明方法的原型:使用限定符extern和其他限定符(local、protected、vietual):class packet

extern protected virtual function int send(int value);

                 限定符             方法原型

endclass

其次:在类外定义完整的方法实现:使用类名与一对冒号::对方法名做限定

     function int packet :: send(int value);   //注意是对方法名send的限定

     ...

     endfunction

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值