Casting from parent class to child class

Hi,

please Consider below the representative code of the problem I am facing while overriding certain behavior of 3rd party VIP/UVC.

//Base item class in UVC code
  class base; 
    int b; 
  endclass
  
 class main_base; 
    int a;
    int b; 
  endclass


//Extending the base item class of UVC and adding 1 more field from my test bench
  class child extends base;
    int c;
  endclass
  
  class main_child extends main_base;
    int c;
  endclass
  
  
//From the test bench I am casting the parent class handle to child and was able to successfully cast the handle and populate the new field "c" in extended class and final write to analysis port
    base base_obj_1;
    child child_obj_2 = new;
    child child_obj_1; 
    base_obj_1  = new; 
    base_obj_1 = child_obj_2;

    $cast(child_obj_1,base_obj_1); 

     base_obj_1.b = 5;   
     child_obj_1.c = 10;
    
   analysis_port.write(base_obj_1);

//In UVC sequence I have get call to the object and then fetched object fields are used to populated another class main_base.

I am extending the UVC sequence in my env to fetch child class field “c” and populate main child class field “c” with it.

base base_obj_2;
child child_obj_2;
main_base main_base_obj_1;
main_child main_child_obj_1;

   analysis_fifo.get(base_obj_2);

  mani_base_obj_1.a = xyz;
   main_base_obj_1.b = base_obj_2.b;
$cast(main_child_obj_1,main_base_obj_1);
  main_child_obj_1.c = child_obj_2.c; // This is what I intended to do and not been able to do successfully
  //I can not use base_obj_2.c as I will get compile time error.
  //I tried casting base_obj_2 to child_obj_2 as above after get port method but gets value 0 and not what was sent/written suing write method.

Any suggestion how can i cast the parent class to child class after the get call.

Regards

In reply to manik16:
What is c1?

In reply to dave_59:

Hi Dave,

I have removed some typos in above example .

c1 is handle to child class.

Regards

In reply to manik16:
Where do main_base_obj_1 and child_obj_2 get their handles?

I would really help if you created a self-contained example of what you are trying to do.

In reply to manik16:

Your code is very difficult to read. I don’t see why you have 2 child classes before the analysis port write when you could just set all values in the first child class and assign that to the base class handle.

After you perform the ‘get’ call, there is no reason why you can’t cast base_obj_2 to child_obj_2. If it’s not working, then you are doing something else wrong. How did you parameterize the uvm_analysis_port and uvm_tlm_analysis_fifo?

In reply to manik16:

Your code is not difficult to read, but you are doing strange and confusing things. An example

child child_obj_2 = new;  // constructing an object child_obj_2
child child_obj_1; 
base_obj_1  = new;        // constructing an object  base_obj_1
base_obj_1 = child_obj_2; // overrirding your base_obj_1 with child_obj_2

You have now 2 refernces to 1 object. Is this really your intention?

In reply to chr_sue:

Hi ,

Yes I am doing strange things indeed :-) but reason was because casting was not working as expected in normal way.

Both derived class(MY Test Bench) and parent class(UVC) in my env are registered in factory.
I have factory override of base class with derived class.
In my TB I am populating the fields of base class properties
base.a = x;
base.b = y;
base.c = z;

And now under some condition I need to populate the properties of derived class as well.
child.d = xyz;

I can not do base.d = xyz as I will get compile error.

so I need to cast back base class to derived class before I do child.d = xyz

I created base class object using create method
Ideally for my case $cast(child,base) should work as my factory override would point create call of base object to child class type.

However somehow that was not working in my env. May I should stop here itself and first debug that before moving ahead and using workarounds.

Anyways I found a workaround. I created an object of child class child_obj_2 and then copy this to base class object base_obj_1 and then do the casting, so that my base class object explicitly points to child class type when casting was executed.

I finally write base class object to write port and give it to UVC sequence to process.

In UVC sequence I have corresponding get call . transaction type on analysis port/export is base class type.

After get call I need to access the newly added properties of derived class from UVC sequence. Now to be able to that I again need to cast base class object that I have received through get call to the child class handle . This is not working.

I accept that my example is not illustrative , but code is spread across many components , will try to create small representative test as Dave suggested.

Regards

In reply to dhserfer:

Hi

I acknowledge that example is not very illustrative , will try to put a better example.

2 child classes are required because first child class is a sub transaction item (has some but not all properties of main transaction item ), Ideally main transaction item could have been extended from sub transaction item class but this arrangement is in 3rd party IP and not in my control.

As you said I also expected that cast in my env should work seemless because I have factory override of base class with derived class so when I create a base class object I should have been able it to cast to derived class as factory would have already pointed base class to derived class type.

But that is not working in my env, working in small test on MTI.

Regards
Manik

In reply to manik16:

It becomes more and more confusing to me.
I understood you have an UVC which is RO for you, but you know the source code, I guess.
In this case it is common and useful practice to extend classes from your UVC to add more functionality.
Each extended class has the content of the base class (here from your UVC) and the added data members, methods etc.
If you want to access the data fields comimng from your base class you can do this using the extended class. You don’t have to do any casting.

In reply to manik16:
A couple of thing that need clarification

Are base and main_base both derived from uvm_sequence_item? You can never upcast or downcast a handle unless the source and destination class variables are part of the same inheritance lineage. As you have written the example, you could never cast a base and a main_base object. But if they are both uvm_sequence_items (or uvm_objects) You can always assign a class variable of an extended class type to one of its base classes. Then you can use $cast to check what kind extended class object it holds

uvm_sequence_item obj;

  analysis_fifo.get(obj);
 
  if($cast(main_child_obj_1,obj))
    // here you can access main_child_obj_1.c
  else if ($cast(child_obj_1,obj))
    // here you can access child_obj_1.c
  else
    // this would be an error as you don't know what class type you got


That same issue holds for overriding class types with the factory - the overridden class type must be an extension of the base class you are overriding.

BTW, I recommend against using parent and child when referring to OOP inheritance. Parents create(construct) children and they are distinct objects from their parents. When you inherit property, that property becomes yours and all your property belongs to one object. Use base and extended.

The UVM uses terms parent and child to refer to relationships between objects when build a hierarchical tree/graph structure. The class uvm_component has a handle to its parent and handles to all its children so that you can traverse the hierarchical structure. This terminology is used in most programming languages and is independent of OOP.