** 子类句柄仅可以指向子类对象,不可以指向父类对象 **
** 父类句柄可以指向父类对象,同时也可以指向子类对象,但是仅可以访问子类对象中的父类变量和方法 **
通过一个例子来理解类的多态,以及虚方法的使用:
1.首先定义一个基类 donkey,并根据该基类派生一个子类baby_donkey;
父类donkey 中实现两个方法,分别为 information( ) 和 favourite_food( ), 其中第二个方法被定义为虚方法。子类baby_donkey实现两个同名方法,如代码所示:
class donkey;
string color = "White";
int weight = 150;
int price = 500;
task information();
$display("@@ This is the father donkey, color is %s, weight = %0d @@", this.color, this.weight);
endtask
virtual task favourite_food(input string food);
$display("@@ Father donkey loves %s @@", food);
endtask
endclass
//----------------------------------------------------------------------------------------
class baby_donkey extends donkey;
string color = "Black";
int weight = 130;
int price = 250;
task information();
$display("@@ This is the baby donkey, colocr is %s, weight = %0d @@", this.color, this.weight);
endtask
virtual task favourite_food(input string food);
$display("@@ Baby donkey loves %s @@", food);
endtask
endclass
2. 声明父类句柄 dk,dk1;为父类donkey开辟空间,将句柄dk1指向该对象。
声明子类句柄 b_dk,b_dk1,b_dk2;为子类开辟空间,将句柄b_dk指向该对象。
donkey dk, dk1;
baby_donkey b_dk, b_dk1, b_dk2;
b_dk = new();
dk1 = new();
【情况一】 将子类句柄直接赋值给父类句柄
将子类句柄传递给父类句柄,父类句柄指向该子类句柄所指向的对象;
通过父类句柄调用同名非虚方法时,父类中的方法会被调用;调用虚方法时,则会根据句柄指向的对象类型调用相应的方法。虚方法的调用与句柄类型无关,仅与句柄指向的类型有关。
module tb;
initial begin
string food = "Grass";
donkey dk, dk1;
baby_donkey b_dk, b_dk1, b_dk2;
b_dk = new();
dk1 = new();
//basic class handle point to child class object by passing the child handle to
parent class
dk = b_dk;
dk.information(); //parent handle call non-virtual method
dk.favourite_food(food); //parent handle call virtual method
b_dk.information(); //child handle call non-virtual method
b_dk.favourite_food(food); //parent handle call virtual method
$display("@@ Baby Price: %0d @@", b_dk.price);
$display("@@ Parent Price: %0d @@", dk.price);
@@ This is the father donkey, color is White, weight = 150 @@
@@ Baby donkey loves Grass @@
@@ This is the baby donkey, colocr is Black, weight = 130 @@
@@ Baby donkey loves Grass @@
@@ Baby Price: 250 @@
@@ Parent Price: 500 @@
【情况二】 通过 $cast 动态转换,将父类句柄转换为子类句柄
通过 $cast 动态转换父类句柄到子类句柄的转换,首先要确保该父类句柄所指向的对象是目标子类句柄类型的对象;如果父类句柄指向的是父类对象,则不能通过动态转换的方式完成句柄类型的转换,因为子类句柄指向父类对象是非法的。
//parent class handle point to child class object, $cast the parent handle to child
handle
$cast(b_dk1, dk);
//parent handle already point to child object, so it's legal to $cast the parent handle to child handle
//now b_dk1, b_dk, dk point to the same object which is allocated by: baby_donkey b_dk = new();
b_dk1.information();
b_dk1.favourite_food(food);
@@ This is the baby donkey, colocr is Black, weight = 130 @@
@@ Baby donkey loves Grass @@
【情况三】 错误的句柄类型转换,父类句柄直接赋值给子类句柄
父类句柄指向父类对象,通过 $cast 将父类句柄转换为子类句柄会失败;
直接将父类句柄赋值给子类句柄同样是非法操作。
将父类句柄dk1复制给父类句柄dk,原来指向子类对象的父类句柄dk不再指向子类对象,而指向dk1所开辟的父类对象空间。
//parent class handle point to parent class object, illegal to $cast the parent handle to child handle
b_dk2 = dk1; // illegal
$cast(b_dk2, dk1); // illegal since parent handle dk1 points to the parent object
dk = dk1;
dk.information();
dk.favourite_food(food);
@@ This is the father donkey, color is White, weight = 150 @@
@@ Father donkey loves Grass @@