4

Is it possible to pass a type argument to function so that create_eclass* function can only be written once by passing class type argument to it ?

class bclass;

virtual function void print();
    $display("Base Class");
endfunction

endclass

class eclass1 extends bclass;

    function void print();
        $display("Extended Class1");
    endfunction

endclass

class eclass2 extends bclass;

    function void print();
        $display("Extended Class2");
    endfunction
endclass

program Test ;
    bclass q[$];

    function create_eclass1();
        bclass     b;
        eclass1    e;
        e=new();
        $cast(b,e);
        q.push_back(e);
    endfunction

    function create_eclass2();
        bclass     b;
        eclass2    e;
        e=new();
        $cast(b,e);
        q.push_back(e);
    endfunction

    initial
    begin
        create_eclass1();
        create_eclass2();
        foreach(q[i]) q[i].print();
    end
endprogram
Jean
  • 21,665
  • 24
  • 69
  • 119

2 Answers2

5

Yes, you can do this by creating an object that acts as a proxy for the type you want to create. This pattern of code is used in the UVM factory.

typedef bclass; // this would be uvm_object in the UVM

interface class object_wrapper; // like a virtual class except it only contains pure virtual methods
   pure virtual function bclass create;
endclass
   
class object_registry#(type T) implements object_wrapper;
   typedef object_registry#(T) this_type;
   local static this_type _singleton; // only one object for each class type
   local function new;
   endfunction
   static function object_wrapper get;
      if (_singleton == null) _singleton = new;
      return _singleton;
   endfunction // if
   virtual function T create;
      create = new;
   endfunction
endclass

The rest of this code is mostly the same as the code in your original example. I've just registered the classes by adding the typedef's which causes the static variables and methods in object_registry to come into existence.

class bclass;

   virtual function void print();
      $display("Base Class");
   endfunction
   
endclass
   
class eclass1 extends bclass;
   typedef object_registry#(eclass1) type_id;
   
   function void print();
      $display("Extended Class1");
   endfunction
   
endclass
   
class eclass2 extends bclass;
   typedef object_registry#(eclass2) type_id;
   function void print();
      $display("Extended Class2");
   endfunction
endclass
   
module Test ;
   bclass q[$];
   
   function void create_eclass(object_wrapper h);
      q.push_back(h.create());
   endfunction

   object_wrapper a1,a2;
   
   initial
     begin   
        create_eclass(eclass1::type_id::get() );
        create_eclass(eclass2::type_id::get() );
    // or another way - 
    a1 = eclass1::type_id::get();
    a2 = eclass2::type_id::get();
        create_eclass(a1 );
        create_eclass(a2 );
        create_eclass(a2 );
        create_eclass(a1 );
    
        foreach(q[i]) q[i].print();
     end
endmodule

I have a paper that explains more of this factory pattern code in detail.

dave_59
  • 39,096
  • 3
  • 24
  • 63
1

A colleague of mine suggested this solution similar to what Dave suggested.

virtual class eclass_creator #( type T = bclass );
  static function T create(int k) ;
    create = new(k) ;
  endfunction
endclass

This allows to create a scoped constructor.

class bclass;
    int i;
    function new(int k);
        i=k;    
    endfunction
    virtual function void print();
        $display("Base Class %0d",i);
    endfunction
endclass

class eclass1 extends bclass;
    function new(int k);
        super.new(k);    
    endfunction
    function void print();
        $display("Extended Class1 %0d",i);
    endfunction
endclass

class eclass2 extends bclass;
    function new(int k);
        super.new(k);    
    endfunction
    function void print();
        $display("Extended Class2 %0d",i);
    endfunction
endclass

program Test ;
    bclass q[$];

    function void push(bclass inclass);
       q.push_back(inclass);
    endfunction

    initial
    begin
        push(eclass_creator #(eclass1)::create(5));
        push(eclass_creator #(eclass2)::create(10));
        foreach(q[i]) q[i].print();
    end
endprogram
Jean
  • 21,665
  • 24
  • 69
  • 119