module factory_override
import uvm_pkg::*;
`include "uvm_macros.svh";
class comp1 extends uvm_component;
`uvm_component_utils(comp1)
function new(string name = "comp1",uvm_component parent = null );
super.new(name,parent);
$display($sformatf("comp1::%s is created",name));
endfunction
virtual function void hello(string name);
$display($sformatf("comp1::%s is said hello",name));
endfunction
endclass
class comp2 extends comp1;
`uvm_component_utils(comp2)
function new(string name = "comp2",uvm_component parent = null);
super.new(name,parent)
$display($sformatf("comp2::%s is created",name));
endfunction
function void hello(string name)
$diaplay($sformatf("comp2::%s is said hello",name))
endfunction
endclass
comp1 c1,c2;
initial begin
comp1::type_id::set_type_override(comp2::get_type());
c1 = new("c1");
c2 = comp1::type_id::create("c2",null);
c1.hello("c1");
c2.hello("c2");
end
endmodule
打印结果
c1和c2都是comp1类型,但是c1是通过new()函数创建的,所以调用c1.hello()打印comp1::c1 said hello!,而c2是通过工厂创建的,调用c2.hello()打印comp2::c2 said hello!。这说明set_type_override()影响到了由工厂创建的对象,工厂会进行类型替换。
其中comp1::type_id::set_type_override(comp2::get_type())使得comp2覆盖了comp1类型,紧接着对c1和c2对象进行了创建,可以从输出结果看到,c1的所属类型仍然是comp1,c2的所属类型则变成了comp2,这说明了factory的覆盖机制只会影响通过factory注册并且创建的对象。所以通过type_id::create()和factory的类型覆盖可以实现对象所属类型在例化时的灵活替换。在例化c2之前,首先应该用comp2来替换comp1的类型,只有先完成了类型替换,才可以在后面的例化时由factory选择正确的类型。在后面发生了类型替换以后,如果原有的代码不做更新,那么c2句柄的类型仍然为comp1,但是却指向了comp2类型的对象,这就要求comp2应该是comp1的子类,只有这样,句柄的指向才是安全合法的。c2在调用hello()方法时,由于首先是comp1类型,那么会查看comp1::hello(),又由于该方法在定义时被指定为虚函数,这就通过了多态性的方法调用,转而调用了comp2::hello()函数,因此,打印的结果是comp2::c2 said hello!