How to dynamically change base class in UVM

Hi,

I am looking for a way that dynamically change the base class, can somebody give me a hint?

Without plugin code,
The uvm_object hierarchy looks like this:
C ← B ← A ← uvm_object
In testcase, using factory_override, B_type override A_type.
In command line, using C_type override B_type by using +uvm_set_type_override=A,C
It works fine that A2 is created as an C type instance.

Now I want to plugin a piece of code to constrain B, with minimal change(don’t change factory_override in the test), is it possible to get the C type instance applied BB constraint? In other words, I want to get a C type instance, whose pkt_type is IPV6.
So far, I tried to use +uvm_set_type_override=B,BB +uvm_set_type_override=A,C. But it didn’t work.

module tb;
import uvm_pkg::*; 
`include "uvm_macros.svh"
   
class A extends uvm_object;
   rand bit[7:0] pkt_len;
   constraint pkt_len_c {
      pkt_len inside {[1:10]};
   }

   `uvm_object_utils_begin(A)
      `uvm_field_int(pkt_len, UVM_ALL_ON)
   `uvm_object_utils_end
   
   function new(string name="A");
      super.new(name);
   endfunction // new
endclass // A

typedef enum {ETH, IPV4, IPV6} pkt_type_e;

class B extends A;
   rand  pkt_type_e pkt_type;
   A A_obj;
   
   constraint b1_cs {
      pkt_type == IPV4;
   }
   
   `uvm_object_utils_begin(B)
      `uvm_field_enum(pkt_type_e, pkt_type, UVM_ALL_ON)
      `uvm_field_object(A_obj, UVM_ALL_ON)
   `uvm_object_utils_end
   
   function new(string name="B");
      super.new(name);
   endfunction // new

   function void build_phase(uvm_phase phase);
      A_obj = A::type_id::create("A");
   endfunction // build_phase
endclass // A

//-----------------------------------------------------------
// PLUGIN CODE
//-----------------------------------------------------------
class BB extends B;
   constraint b1_cs {
      pkt_type == IPV6;
   }  
   `uvm_object_utils(BB)
   function new(string name="BB");
      super.new(name);
   endfunction // new
endclass // BB

//------------------------------------------------------------
// PLUGIN CODE END
//------------------------------------------------------------
   
class C extends B;
   rand bit ocs_en;
   `uvm_object_utils_begin(C)
      `uvm_field_int(ocs_en, UVM_ALL_ON)
   `uvm_object_utils_end

   function new(string name="C");
      super.new(name);
   endfunction // new
endclass // C

class test1 extends uvm_test;
   A A1, A2;

   `uvm_component_utils(test1)
   function new(string name="test1", uvm_component parent);
      super.new(name, parent);
   endfunction // new

   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
      `uvm_info(get_full_name(), ", full_path:", UVM_LOW)

      factory.set_type_override_by_type(A::get_type(), B::get_type(), 0);
      factory.print();
      A2 = A::type_id::create("A2");
      assert(A2.randomize());
      A2.print();

   endfunction // build_phase
endclass // test1
   
initial run_test("test1");
endmodule

I find the question a little confusing. However, as per what I have understood, the solution could be to extend BB from C rather than B, so that you could directly override the constraint and everything else could be the same.

Something like below:

class BB extends C;
   constraint b1_cs {
      pkt_type == IPV6;
   }  
   `uvm_object_utils(BB)
   function new(string name="BB");
      super.new(name);
   endfunction // new
endclass // BB

Post this, you could use the overriding as +uvm_set_type_override=A,BB!!