Why we require down cast. I will explain you by the following example.
See one interesting case below. If base class handle(assigned to extended class object) calls a function of extended class and that function has a member(ext_class_var, in $display) which is not defined in base class, it will show its value in $display. (That fuction must be defined as virtual in base class, otherwise it will execute the defination of base class function only) But, however, is we try to access that member(ext_class_var) separately with base class handle (like here changing its value to 5), it will show an error since that memeber is not present in base class.
Output:virtual class animal; int age=-1; function new(int a = 0); age = a; endfunction : new virtual function string convert2string(); return $sformatf("Age: %0d", age); endfunction : convert2string virtual function void do_copy(animal copied_animal); age = copied_animal.age; endfunction : do_copy endclass : animal class mammal extends animal; int babies_in_litter; function new(int a = 0, b = 0); super.new(a); babies_in_litter = b; endfunction : new function string convert2string(); return {super.convert2string(), $sformatf("\nbabies in litter: %0d",babies_in_litter)}; endfunction : convert2string function void do_copy(animal copied_animal); mammal copied_mammal; super.do_copy(copied_animal); $cast(copied_mammal, copied_animal); babies_in_litter = copied_mammal.babies_in_litter; endfunction : do_copy endclass : mammal class lion extends mammal; bit is_female; function new(int age = 0, int babies_in_litter = 0, bit is_female = 0); super.new(age, babies_in_litter); this.is_female = is_female; endfunction : new function string convert2string(); string gender_s; gender_s = (is_female) ? "Female" : "Male"; return {super.convert2string(), "\nGender: ",gender_s}; endfunction : convert2string function void do_copy(animal copied_animal); lion copied_lion; super.do_copy(copied_animal); $cast(copied_lion, copied_animal); this.is_female = copied_lion.is_female; endfunction : do_copy endclass : lion class captive_lion extends lion; string name; function new(int age=0, int babies_in_litter = 0, bit is_female=0, string name=""); super.new(age,babies_in_litter, is_female); this.name = name; endfunction : new function string convert2string(); return { super.convert2string(),"\nName: ", name }; endfunction : convert2string function void do_copy(animal copied_animal); captive_lion copied_captive_lion; super.do_copy(copied_animal); $cast(copied_captive_lion, copied_animal); this.name = copied_captive_lion.name; endfunction : do_copy endclass : captive_lion class circus_lion extends captive_lion; byte numb_tricks; function new(int age=0, bit is_female=0, int babies_in_litter = 0, string name="", byte numb_tricks=0); super.new(age,babies_in_litter, is_female, name); this.numb_tricks = numb_tricks; endfunction : new function string convert2string(); return {super.convert2string(),"\n", $sformatf("numb_tricks: %0d",numb_tricks)}; endfunction : convert2string function void do_copy(animal copied_animal); circus_lion copied_circus_lion; super.do_copy(copied_animal); $cast(copied_circus_lion, copied_animal); this.numb_tricks = copied_circus_lion.numb_tricks; endfunction : do_copy endclass : circus_lion module top; circus_lion circus_lion1_h, circus_lion2_h; initial begin circus_lion1_h = new(.age(2), .is_female(1), .babies_in_litter(2), .name("Agnes"), .numb_tricks(2)); $display("\n--- Lion 1 ---\n",circus_lion1_h.convert2string()); circus_lion2_h = new(); $display("\n--- Lion 2 before copy ---\n", circus_lion2_h.convert2string()); circus_lion2_h.do_copy(circus_lion1_h); $display("\n--- Lion 2 after copy ---\n", circus_lion2_h.convert2string()); end endmodule : top
Output :
--- Lion 1 --- Age: 2 babies in litter: 2 Gender: Female Name: Agnes numb_tricks: 2 --- Lion 2 before copy --- Age: 0 babies in litter: 0 Gender: Male Name: numb_tricks: 0 --- Lion 2 after copy --- Age: 2 babies in litter: 2 Gender: Female Name: Agnes numb_tricks: 2
Here do_copy is inherited from base class and every child class has overridden the definition.
Frop top module I am copying circus_lion1_h and circus_lion2_h of type circus_lion. Which call for circus_lion2_h.do_copy(circus_lion1_h) Hence circus_lion1_h as passed as an argument of animal copied_animal.
Basically it is like copied_animal = circus_lion1_h for do_copy.
It is simple OOPs concept, base class is assigned a handle of child class.
But now what if I want to use child class variable (which is not there in base class i.e numb_tricks in circus_lion). I can not use animal copied_animal for that (as numb_tricks is not defined in class type animal). I need to downcast animal copied_animal to circus_lion copied_circus_lion to access numb_tricks.
Remember I can down cast base class variable to child class variable only if base class variable is having handle of child class.
Here $cast(copied_circus_lion, copied_animal); worked becuase copied_animal (variable of type animal) contains handle of circus_lion.
If I pass captive lion as an argument of do_copy, it will give an error.
See below code ( If I change the top module as below, keeping rest of code as it is)
module top; circus_lion circus_lion1_h, circus_lion2_h; captive_lion captive_lion_h; initial begin circus_lion1_h = new(.age(2), .is_female(1), .babies_in_litter(2), .name("Agnes"), .numb_tricks(2)); $display("\n--- Lion 1 ---\n",circus_lion1_h.convert2string()); circus_lion2_h = new(); captive_lion_h = new(); $display("\n--- Lion 2 before copy ---\n", circus_lion2_h.convert2string()); circus_lion2_h.do_copy(captive_lion_h); // Check the change here $display("\n--- Lion 2 after copy ---\n", circus_lion2_h.convert2string()); end endmodule : topOutput :Error-[DCF] Dynamic cast failed testbench.sv, 101 Casting of source class type 'captive_lion' to destination class type 'circus_lion' failed due to type mismatch. Please ensure matching types for dynamic cast
Inside extended class 1 and ext_class_var is 1
Inside extended class 2 and ext_class_var is 2
Inside extended class 3 and ext_class_var is 3
Now where the downcast is required here. Let's say you have another handle of class ext_class_1 as ec_x, which you want to assign to object ec_1 through your base class b_c[0]. You can not do ec_x=b_c[0]; You need to do $cast(ec_x,b_c[0]); Then you can change members through ec_x handle. Essentialy ec_x, ec_1 and bc[0] is now pointing to same object. Output:
Inside extended class 1 and ext_class_var is 5
Inside extended class 2 and ext_class_var is 2
Inside extended class 3 and ext_class_var is 3
credit: https://verificationguide.com/systemverilog/systemverilog-casting/