类变量是变量的值表示对类对象的引用。 像任何其他变量一样,类变量的生命周期取决于它的定义方式和位置(静态,自动或动态)。
类句柄表示对类对象的引用的值。 您永远无法查看或表示句柄的文字值(除特殊句柄:null外)。 您必须在表达式中使用类变量,以便使用存储在变量中的类句柄来引用类对象中的成员或方法。
举例如下:
module top;
class class_name
int i;
endclass
class_name class_variable;;
initial $display("Hello World");
endmodule
你将创建一个静态变量class_name但不包含类对象。 所以没有句柄存在class_name。 现在调用构造函数。
module top;
class class_name
int i;
endclass
class_name class_variable;;
initial $display("Hello World");
initial begin
class_variable = new();
class_variable.i = 1;
$display(class_variable.i);
end
endmodule
new()是一个返回句柄给class_name对象的函数。 class_variable.i表示使用存储在class_variable中的句柄来引用对象,并选择该对象的变量i。 在C / C ++中,这看起来像指针引用class_name-> i; 在SystemVerilog中,你永远不会直接使用这个对象,你总是引用使用存储在类变量中的句柄。
关于句柄的通俗解释(什么是句柄?为什么会有句柄?):
从广义上,能够从一个数值拎起一大堆数据的东西都可以叫做句柄。句柄的英文是"Handle",本义就是"柄",只是在计算机科学中,被特别地翻译成"句柄",其实还是个"柄"。从一个小东西拎起一大堆东西,这难道不像是个"柄"吗?
然后,指针其实也是一种"句柄",只是由于指针同时拥有更特殊的含义——实实在在地对应内存里地一个地址——所以,通常不把指针说成是"句柄"。但指针也有着能从一个32位的值引用到一大堆数据的作用,这不是句柄又是什么?
Windows系统中有许多内核对象(这里的对象不完全等价于"面向对象程序设计"一词中的"对象",虽然实质上还真差不多),比如打开的文件,创建的线程,程序的窗口,等等。这些重要的对象肯定不是4个字节或者8个字节足以完全描述的,他们拥有大量的属性。为了保存这样一个"对象"的状态,往往需要上百甚至上千字节的内存空间,那么怎么在程序间或程序内部的子过程(函数)之间传递这些数据呢?拖着这成百上千的字节拷贝来拷贝去吗?显然会浪费效率。那么怎么办?当然传递这些对象的首地址是一个办法,但这至少有两个缺点:
- 暴露了内核对象本身,使得程序(而不是操作系统内核)也可以任意地修改对象地内部状态(首地址都知道了,还有什么不能改的?),这显然是操作系统内核所不允许的;
- 操作系统有定期整理内存的责任,如果一些内存整理过一次后,对象被搬走了怎么办?
所以,Windows操作系统就采用进一步的间接:在进程的地址空间中设一张表,表里头专门保存一些编号和由这个编号对应一个地址,而由那个地址去引用实际的对象,这个编号跟那个地址在数值上没有任何规律性的联系,纯粹是个映射而已。
在Windows系统中,这个编号就叫做"句柄"。