1
class中的变量、宏定义等称为类的属性,函数和任务称为类的方法
2
声明对象时可以指定input/output/inout/ref
3
复制对象,复制的是句柄而不是对象的内容。
类的每个对象,对于属性、方法等都有自己的副本
4
?
1 2 3 4 5 6 |
class c;
... endclass c c0;
|
//“c0”就是对象c0的句柄,在此处仅相当于一个name,类似于仅是创建了一个c类型的变量c0,而这个变量保存类c对象
的句柄,但其初始化值为NULL
此时,这个对象时不存在,也不包含任何实际的句柄,知道进行初始化:c0 = new()
此时,对象c0的句柄尚未被初始化,因此,为默认值;Null。因此,检测一个对象是否被初始化,与值Null进行比对即可:
值为Null的句柄不可以访问非静态成员和虚方法
?
1 2 3 4 5 6 7 8 |
class obj_example;
...
endclass
task task1(integer a, obj_example myexample);
if (myexample == null ) myexample = new ; //初始化
endtask
|
4_1
类对象支持的算术/逻辑运算:
—支持的操作—–操作对象—-含义
== 对象/Null
!= 同上
=== 同上
!== 同上
条件操作
类型兼容的对象间互相赋值
赋值Null
5
初始化函数new(),非阻塞,没有返回值类型(但初始化过程中,但暗含的返回值类型就是赋值等号左侧变量的类型)
new()函数,可不人为定义,在对象初始化时会调用默认的new函数,也可以人为定义new函数,以便规定初始化操作。
6、基类、扩展类new()函数的执行:
先调用基类的new函数——super.new(),
eg:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
class C;
int c1 = 1 ;
int c2 = 1 ;
int c3 = 1 ;
function new ( int a);
c2 = 2 ;
c3 = a;
endfunction
endclass
class D extends C;
int d1 = 4 ;
int d2 = c2;
int d3 = 6 ;
function new ;
super . new (d3);
endfunction
endclass
D obj_d;
obj_d = new (d3);
|
解释:
会先执行基类C的初始化new函数(即类C的属性、方法的初始和定义等),c1 = 1,c2 = 2;
c3,基类C中new函数的输入参数a此时为d3,但此时d3尚未定义,所以,c3为未定义值;
基类的各种初始完成后开始进行扩展类的初始操作,即执行扩展类的new函数,d1 = 4,d2 = 2(基类中的变量c2,基类此时已初始化完成,所以c2为确定的值),d3 = 6,
7
类声明中的静态属性,只创建、初始化一次,之后则可以为所有的对象访问,并且,可以以无创建对象的方式被访问
?
1
2
3
4
|
class Packet ;
static integer fileID = $fopen( "data" , "r" );
endclass
|
8
类声明中的静态方法,类的全范围内可以调用,也可以无创建对象的方式被访问,不可以访问非静态的成员(属性和其他方法);
不能声明为virtual,声明中不能使用this句柄;
?
1
2
3
4
5
6
7
8
9
|
static task t();
...
endtask //正确格式,说明了类中方法的lifetime(理解为:存活时间)
task static t();
...
endtask //错误格式,说明的是方法的参数及方法声明中的各个变量的lifetime
|
9
this指针,涉及类的属性、变量参数、对象本地的变量参数或方法,应用在非静态方法中
10
类对象的复制:
(1)
class c;
…
endclass
?
1
2
3
4
|
c c0, c1;
c0 = new ();
c1 = c0;
|
解释:new只执行一次,只涉及到一个句柄,所以说,只有一个对象,只是对于对象的句柄而言有两个名字,分别为:c0和c1
(2)
?
1
2
3
4
5
6
7
8
|
class c;
...
endclass
c c0, c1;
c0 = new ();
c1 = new c0;
|
解释:new函数执行两次,创建了两个对象:c0和c1,c1是复制的c0,但只是复制了c0的句柄,也可以认为是一个对象有两个名字
注:这种方式的复制,对于嵌入式的约束,在新的对象中为Null
(3)
?
1
2
3
4
5
6
7
8
9
|
class c;
...
endclass
c c0, c1;
c0 = new ();
c1 = new ();
c1.copy(c0);
|
解释:c0中的任何内容全部复制给了c1,更常用。
11
扩展类对象的句柄可赋值给基类变量
?
1
2
3
4
5
6
7
8
9
10
11
|
class c;
class cc extends c;
......
endclass
endclass
c c0;
cc cc0;
cc0 = new ();
c0 = cc0;
|
注:扩展类中的属性或方法被重写覆盖时,通过以上方法,可以获得基类中各成员的原始值/内容
且当基类中为纯虚方法、扩展类中方法的定义也必然是虚方法,这种情况下,基类变量可以直接访问扩展类的方法
?
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class c;
class cc extends c;
int i = 1 ;
int i = 2 ;
endclass
endclass
c c0;
cc cc0;
cc0 = new ();
c0 = cc0;
j = c0.i; //j = 1,而不是等于2,所以说,扩展类中变量i进行何种操作,基类都会保留变量i的原始值
|
注:扩展类声明变量(cc cc0;)可以赋值给基类声明变量(c c0;)或更高层次类的声明,反过来则是错误的,除非基类中调用了扩展类
12
super 访问当前类的上一层次的类的成员
?
1
2
3
4
|
super . new //先于当前类的new执行,可以用户手动添加,或者编译器会自动添加执行super.new的阶段
function new (); //扩展类中new函数
super . new ( 5 ); //启动当前类基类的new函数,并且是带有参数的,会传递给基类的初始化函数
|
13
类中数据的封装与保护:定义成员关键字含义local和protected
?
1
2
3
|
local //只有当前类中方法可以访问,不同对象间可以互相访问,但扩展类中方法不能访问
protected //同local定义基本相同,唯一差别在于可以被继承、扩展类可以访问
|
14
类中属性/成员:const、local、protected、static
类中方法:virtual
const:定义只读变量,分为global const和instace const,
区别在于:前者声明时进行赋值,同static,所有的对象均可访问,且内容一样;后者只是声明,实例化时才会赋值
?
1
2
3
|
const int max_size = 9 * 1024 ; // global constant,也可以声明为static
const int size; // instance constant
|
15
抽象类:可以看作是模板或原型
?
1
2
3
4
|
virtual class BasePacket;
...
endclass
|
无法直接创建抽象类的对象.
纯虚方法:定义在抽象类中的虚方法,具体的实现则是在扩展类(非抽象类)中定义完成的
?
1
2
3
4
5
6
7
8
9
10
11
|
virtual class BasePacket;
pure virtual function integer send(bit[ 31 : 0 ] data); // No implementation
endclass
class EtherPacket extends BasePacket;
virtual function integer send(bit[ 31 : 0 ] data);
// body of the function
...
endfunction
endclass
|
当基类中为纯虚方法、扩展类中方法的定义也必然是虚方法,这种情况下,基类变量可以直接访问扩展类的方法
?
1
2
3
4
5
6
7
8
9
10
|
BasePacket packets[ 100 ];
EtherPacket ep = new ; // extends BasePacket
TokenPacket tp = new ; // extends BasePacket
GPSSPacket gp = new ; // extends EtherPacket
packets[ 0 ] = ep;
packets[ 1 ] = tp;
packets[ 2 ] = gp;
packets[ 1 ].send(); //invoke the send method associated with the TokenPacket class
|
16
类的嵌套:嵌套的类可以访问被嵌套类的local、protected、static等成员,有完全访问权
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class Outer;
int outerProp;
local int outerLocalProp;
static int outerStaticProp;
static local int outerLocalStaticProp;
class Inner; //类Inner为嵌套类
function void innerMethod(Outer h); //类Outer声明
outerStaticProp = 0 ; // Legal, same as Outer::outerStaticProp
outerLocalStaticProp = 0 ; // Legal, nested classes may access local's in outer class
outerProp = 0 ; // Illegal, unqualified access to non-static outer
h.outerProp = 0 ; // Legal, qualified access.
h.outerLocalProp = 0 ; // Legal, qualified access and locals to outer class allowed.
endfunction
endclass
endclass
|
17
外部定义:在类内带extern关键字进行声明,类外定义时,需指明类作用域,用”::”符号
例子1:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class Packet;
Packet next;
function Packet get_next(); // single line
get_next = next;
endfunction
// out-of-body (extern) declaration
extern protected virtual function int send( int value);
endclass
function int Packet::send( int value);
// dropped protected virtual, added Packet::
// body of method
...
endfunction
|
例子2:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
typedef real T;
class C;
typedef int T;
extern function T f();
extern function real f2();
endclass
function C::T C::f(); // the return must use the scope resolution,以区分"typedef real T"和"typedef int T"
return 1 ;
endfunction
function real C::f2();
return 1.0 ;
endfunction
|
例子3:
?
1
2
3
4
5
6
7
8
9
|
typedef int T;
class C;
extern function void f(T x); //原型中,T采用的是"typedef int T"
typedef real T;
endclass
function void C::f(T x); //error,在此处采用的是类中声明的"typedef real T"
endfunction
|
注:最好是用作用域符号”::”
18
参数化类:类似于C++中的模板
例子1:
?
1
2
3
4
5
6
7
8
|
class vector #( int size = 1 );
bit [size- 1 : 0 ] a;
endclass
vector #( 10 ) vten; // object with vector of size 10
vector #(.size( 2 )) vtwo; // object with vector of size 2
typedef vector#( 4 ) Vfour; // Class with vector of size 4
|
例子2:
?
1
2
3
4
5
6
7
8
9
10
|
class stack #(type T = int );
local T items[];
task push( T a ); ... endtask
task pop( ref T a ); ... endtask
endclass
stack is; // default: a stack of int’s
stack#(bit[ 1 : 10 ]) bs; // a stack of 10-bit vector
stack#(real) rs; // a stack of real numbers
|
例子3
?
1
2
3
4
5
6
|
class C #(type T = bit); ... endclass // base class
class D1 #(type P = real) extends C; // T is bit (the default)
class D2 #(type P = real) extends C #(integer); // T is integer
class D3 #(type P = real) extends C #(P); // T is P
class D4 #(type P = C#(real)) extends P; // for default T is real
|
18_2
还是讲参数化的类:
以两个例子说明参数化的类及声明静态变量时的情况:
eg:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
program param_stack;
class stack #(type T = int );
int m_cnt;
static int counter = 2 ;
function new ;
m_cnt = counter++;
endfunction: new
endclass: stack
class stacked extends stack #(real);
...
endclass: stacked
typedef stack #( byte ) stack_byte;
typedef stack #() stact_int;
stack_byte S1 = new ();
stack_byte S2 = new ();
stack S3 = new ();
stack #(bit) S4 = new ();
stacked S5 = new ();
initial begin
$display ( "Counter value of S1 instance = %0d" , stack #( byte )::counter);
$display ( "Counter value of S2 instance = %0d" , stack_byte:: counter);
$display ( "Counter value of S3 instance = %0d" , stack #()::counter);
$display ( "Counter value of S4 instance = %0d" , stack#(bit)::counter);
$display ( "Counter value of S5 instance = %0d" , stacked::counter);
end
endprogram: param_stack
|
打印的值依次为:
?
解释:虽然静态变量只会存在一个副本。
由于S1和S2均由stack_byte创建,所以S1时counter的值为3,S2为4;
S3则是由默认参数类创建,等同于程序中的stack_int,counter值为3;
S4则是type为bit的类创建,counter同样为3;
S5亦然。
即当参数类的参数不同时,他们是不同的类。