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.
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code your testbench here | |
// or browse Examples | |
// Code your testbench here | |
// or browse Examples | |
// base class | |
class base_class; | |
virtual function void display(); | |
$display("Inside base class"); | |
endfunction | |
endclass | |
// extended class 1 | |
class ext_class_1 extends base_class; | |
int ext_class_var = 1; | |
function void display(); | |
$display("Inside extended class 1 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// extended class 2 | |
class ext_class_2 extends base_class; | |
int ext_class_var = 2; | |
function void display(); | |
$display("Inside extended class 2 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// extended class 3 | |
class ext_class_3 extends base_class; | |
int ext_class_var = 3; | |
function void display(); | |
$display("Inside extended class 3 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// module | |
module class_polymorphism; | |
initial begin | |
//declare and create extended class | |
ext_class_1 ec_1 = new(); | |
ext_class_2 ec_2 = new(); | |
ext_class_3 ec_3 = new(); | |
//base class handle | |
base_class b_c[3]; | |
//assigning extended class to base class | |
b_c[0] = ec_1; | |
b_c[1] = ec_2; | |
b_c[2] = ec_3; | |
//b_c[0].ext_class_var = 5; Error-[MFNF] Member not found | |
//testbench.sv, 53 "b_c[0]." | |
//Could not find member | |
//'ext_class_var' in class | |
//'base_class' | |
//accessing extended class methods using base class handle | |
b_c[0].display(); | |
b_c[1].display(); | |
b_c[2].display(); | |
end | |
endmodule |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Code your testbench here | |
// or browse Examples | |
// Code your testbench here | |
// or browse Examples | |
// base class | |
class base_class; | |
virtual function void display(); | |
$display("Inside base class"); | |
endfunction | |
endclass | |
// extended class 1 | |
class ext_class_1 extends base_class; | |
int ext_class_var = 1; | |
function void display(); | |
$display("Inside extended class 1 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// extended class 2 | |
class ext_class_2 extends base_class; | |
int ext_class_var = 2; | |
function void display(); | |
$display("Inside extended class 2 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// extended class 3 | |
class ext_class_3 extends base_class; | |
int ext_class_var = 3; | |
function void display(); | |
$display("Inside extended class 3 and ext_class_var is %0d",ext_class_var); | |
endfunction | |
endclass | |
// module | |
module class_polymorphism; | |
initial begin | |
//declare and create extended class | |
ext_class_1 ec_1 = new(); | |
ext_class_2 ec_2 = new(); | |
ext_class_3 ec_3 = new(); | |
ext_class_1 ec_x = new(); | |
//base class handle | |
base_class b_c[3]; | |
//assigning extended class to base class | |
b_c[0] = ec_1; | |
b_c[1] = ec_2; | |
b_c[2] = ec_3; | |
//ec_x = b_c[0]; //Error-[SV-ICA] Illegal class assignment | |
$cast(ec_x,b_c[0]); | |
ec_x.ext_class_var = 5; | |
//accessing extended class methods using base class handle | |
b_c[0].display(); | |
b_c[1].display(); | |
b_c[2].display(); | |
end | |
endmodule |
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/