多态
实现多态有以下方法:虚函数、虚类、重载
多态的目的就是实现函数的重载,从而使得一个子类的指针在以父类的类型传递时,表现出的行为依然是子类的行为。
虚函数 virtual function:
- 不使用 virtual,父类句柄虽指向子类对象,但调用的仍是父类本身的函数
- 使用 virtual,父类句柄指向子类对象,调用的是子类的函数
// 不使用virtual,父类句柄虽指向子类对象,但调用的仍是父类本身的函数
class father;
function display();
$display("This is Father!!");
endfunction
endclass
class son extends father;
function display();
$display("This is Son!!");
endfunction
endclass
module tb;
father father_inst;
son son_inst;
initial begin
son_inst = new(); // 子类对象
father_inst = son_inst; // 父类指针指向子类
father_inst.display(); // 父类指针依旧调用父类函数
son_inst.display();
end
endmodule
// 使用virtual,父类句柄指向子类对象,调用的是子类的函数
class father;
virtual function display(); // 父类定义函数为virtual,其子类同名函数默认为virtual
$display("This is Father!!");
endfunction
endclass
class son extends father;
function display(); // 父类定义函数为virtual,其子类同名函数默认为virtual
$display("This is Son!!");
endfunction
endclass
module tb;
father father_inst;
son son_inst;
initial begin
son_inst = new(); // 子类对象
father_inst = son_inst; // 父类指针指向子类
father_inst.display(); // 父类指针调用子类函数
son_inst.display();
end
endmodule
- 声明 virtual function 时,根据对象来决定调用
- 未声明 virtual function 时,根据句柄来决定调用
class bird;
virtual function void hungry(); // 父类virtual函数
$display("father virtual function");
endfunction
function void hungry2();
$display("father function");
endfunction
endclass
class parrot extends bird;
function void hungry(); // 子类函数与父类virtual函数同名,默认为virtual
$display("son virtual function");
endfunction
function void hungry2();
$display("son function");
endfunction
endclass
module tb;
bird A;
parrot B;
initial begin
A = new();
B = new();
A = B; // 父类指针指向子类 (父类可以指向子类,因为父类有的对象和函数,子类都有)
A.hungry(); // 父类指针指向子类,子类函数与父类virtual函数同名情况下, 父类指针指向子类函数
A.hungry2(); // 子类函数与父类函数同名,但父类函数不是virtual, 父类指针不可以指向子类函数
B.hungry();
B.hungry2();
end
endmodule
$cast:子类指向父类
- 子类指针指向 指向子类的父类指针 (其实还是子类指向子类)
$cast(B,A)
class bird;
virtual function void hungry(); // 父类virtual函数
$display("father virtual function");
endfunction
function void hungry2();
$display("father function");
endfunction
endclass
class parrot extends bird;
function void hungry(); // 子类函数与父类virtual函数同名,默认为virtual
$display("son virtual function");
endfunction
function void hungry2();
$display("son function");
endfunction
endclass
module tb;
bird A;
parrot B;
initial begin
A = new();
B = new();
A = B; // 父类指针指向子类
if(!$cast(B,A))begin // 子类指针B指向 指向子类的父类指针A (其实还是子类指向子类)
$display("B = A; failed");
end
else begin
$display("B = A; OK !!!!"); // 这种$cast是合法的,效果同直接
end
A.hungry(); // 父类指针指向子类,子类函数与父类virtual函数同名情况下, 父类指针指向子类函数
A.hungry2(); // 父类指针指向子类,子类函数与父类函数同名,但父类函数不是virtual, 父类指针仍然指向父类函数
B.hungry(); // 子类指针B指向 指向子类的父类指针A (B绕了一圈指向自己)
B.hungry2();
end
endmodule
- 子类指针指向 指向孙类的父类指针 (其实还是子类指向孙类)
$cast(B,A)
class bird;
virtual function void hungry(); // 父类virtual函数
$display("father virtual function");
endfunction
function void hungry2();
$display("father function");
endfunction
endclass
class parrot extends bird;
function void hungry(); // 子类函数与父类virtual函数同名,默认为virtual
$display("son virtual function");
endfunction
function void hungry2();
$display("son function");
endfunction
endclass
class dog extends parrot;
function void hungry();
$display("grandson virtual function");
endfunction
function void hungry2();
$display("grandson function");
endfunction
endclass
module tb;
bird A;
parrot B;
dog C;
initial begin
A = new();
B = new();
C = new();
A = C;
if(!$cast(B,A))begin
$display("B = A; failed");
end
else begin
$display("B = A; OK !!!!");
end
A.hungry(); // 父类指向孙类,函数为virtual,父类指针调用孙类同名函数
A.hungry2(); // 父类指向孙类,函数不是virtual,父类指针调用父类函数
B.hungry(); // 子类指向 指向孙类的父类指针,函数是virtual,子类指针调用孙类同名函数
B.hungry2(); // 子类指向 指向孙类的父类指针,函数不是virtual,子类指针调用子类函数
end
endmodule
抽象类 virtual class:
- virtual class (抽象类):可以被扩展但是不能被直接例化
- 由抽象类扩展而来的类,只有在所以 pure virtual 纯虚方法都有实体的时候才能被例化。