1、浅复制:
Packet p1;
Packet p2;
p2 = new p1; // Shallow copy: Only copy object, Objects in class packet are not copied, only their handles;
先说结论:
1.
深复制和浅复制都是指复制一个对象,而不是句柄
。(区别于句柄的复制)
2.
浅复制: 先创建了一个新的对象,从另一对象复制了其各个类属性。所有变量都被复制:整数、字符串、实例句柄等。然而,类属性中的对象本身并没有被复制,只有它们的句柄:如果一个类包含指向另一个类的句柄,只有最高级的对象被new操作符复制,下一层的对象都不会被复制
3.
深复制:如果一个类包含指向另一个类的句柄,同时会复制类属性中句柄的对象;通常需要使用自定义代码
。
4.
两者主要的区别就在于会不会复制类属性中的对象
;
首先,从类变量的声明及对象的创建讲起:声明一个类变量只是创建了一个对象的名称。因此,
Packet p1;
上面的语句创建了一个变量p1,可以保存类Packet的
句柄
,但是p1的初始值为null。直到创建了Packet类型的实例,对象才存在,p1才包含实际的句柄:
p1 = new;
如果另一个变量声明并将旧句柄 p1 赋给新变量,例如:
Packet p2;
p2 = p1;
那么仍然只有一个对象,可以用p1或p2的名称引用。在这个例子中,new只执行了一次,因此只创建了一个对象。
一、 浅复制
如果将前面的例子重写如下,将会创建 p1 的副本:
Packet p1;
Packet p2;
p1 = new;
p2 = new p1;
最后一条语句中,new操作符被执行了第二次,从而创建了一个新的对象p2,其类属性从p1进行了复制。这被称为浅复制。所有变量都被复制:整数、字符串、实例句柄等。然而,对象本身并没有被复制,只有它们的句柄;与之前一样,创建了同一个对象的两个名称。即使类声明中包含了实例化操作符new,这个情况仍然成立。
对于浅复制来说,
使用类型化的构造函数调用将是非法的
(参见IEEE Standard 2017 – 8.8)。
浅复制的执行方式如下:
(1)为被复制的类类型对象进行分配内存空间。这个分配不会调用对象的构造函数或执行任何变量声明的初始化赋值。
(2)将所有的类属性,包括用于随机化和覆盖率的内部状态,复制到新对象中。对象句柄也会被复制;这包括covergroup对象的句柄。但对于嵌入的 covergroup,会将其句柄在新对象中设置为null。随机化的内部状态包括随机数生成器(RNG)状态、约束的constraint_mode状态、随机变量的rand_mode状态,以及randc变量的循环状态。
(3)将指向新创建的对象的句柄赋值给左侧的变量。
注意:浅复制不会创建新的
覆盖率
对象(covergroup实例)。因此,新对象的属性不会被覆盖率所覆盖。
//Example 1.1
class baseA ;
integer j = 5;
endclass
class B ;
integer i = 1;
baseA a = new;
endclass
class xtndA extends baseA;
rand int x;
constraint cst1 { x < 10; }
endclass
function integer test;
xtndA xtnd1;
baseA base2, base3;
B b1 = new; // Create an object of class B
B b2 = new b1; // Create an object that is a copy of b1
b2.i = 10; // i is changed in b2, but not in b1
b2.a.j = 50; // change a.j, shared by both b1 and b2
test = b1.i; // test is set to 1 (b1.i has not changed)
test = b1.a.j; // test is set to 50 (a.j has changed)
xtnd1 = new; // create a new instance of class xtndA
xtnd1.x = 3;
base2 = xtnd1; // base2 refers to the same object as xtnd1
base3 = new base2; // Creates a shallow copy of xtnd1
endfunction
在最后一条语句中,base3被赋予了base2的浅复制。变量base3的类型是指向基类baseA的句柄。当调用浅复制时,该变量包含对扩展类xtndA实例的句柄。浅复制创建了被引用对象的副本,从而产生了扩展类xntdA的副本实例。然后,将对该实例的句柄赋值给变量base3。
有几点值得注意:
(1)首先,类属性和实例化对象可以直接在类声明中初始化。
(2)其次,浅复制不会复制对象本身。
(3)可以根据需要链接实例限定符以访问对象内部的属性或遍历对象: