Hi I have a confusion regarding virtual methods in system Verilog
this is a code I copied from a blog
class Base;
int unsigned A = 1;
int unsigned B = 2;
function void printA();
$display("Base: A=%0d", A);
endfunction : printA
virtual function void printB();
$display("Base: B=%0d", B);
endfunction : printB
endclass : Base
class Child extends Base;
int unsigned A = 3;
int unsigned B = 4;
function void printA();
$display("Child: A=%0d", A);
endfunction : printA
function void printB();
$display("Child: B=%0d", B);
endfunction : printB
endclass : Child
class Child2 extends Child;
int unsigned A = 5;
int unsigned B = 6;
function void printA();
$display("Child2: A=%0d", A);
endfunction : printA
function void printB();
$display("Child2: B=%0d", B);
endfunction : printB
endclass : Child2
module top();
Base B1;
Child C1;
Child2 C2;
initial begin
B1 = new();
C1 = new();
C2 = new();
B1.printA;// displays 'Base::A is 1'
B1.printB;// displays 'Base::B is 2'
C1.printA;// displays 'Child::A is 3'
C1.printB;// displays 'Child::B is 4'
C2.printA;// displays 'Child2::A is 5'
C2.printB;// displays 'Child2::B is 6'
end
endmodule:top
printA method is not virtual whereas printB is virtual. Since printA is not virual, if I call printA using child class object, I am expecting printA method of the parent class to be excecuted.
Can someone give me a clear idea on this?
In reply to Deepthip:
The type of the class variable alone determines which printA method gets called. Since you override printA in the “child” class, and you use the same class variable type to reference it, the child class method is what gets called.
See my article on OOP inheritance:
Also, see this post about my dislike of parent/child terminology.
In reply to dave_59:
Thanks Dave . I am still confused.But why doesn’t it happen in below code.
typedef enum {IDLE, RUN, P0, P1} cmd_t;
///// Base Class Declaration
class Packet;
/// Properties
cmd_t cmd;
int status;
bit [7:0] data [0:255];
/// Method
function void SetStatus (input int y);
status = y;
$display("base");
endfunction: SetStatus
endclass: Packet
///// Extended Class Declaration
class myPacket extends Packet;
/// Added Properties
bit errBit;
/// Newly Added Method
function bit ShowError();
return(errBit);
endfunction: ShowError
/// Overriding Method
function void SetStatus (input int y);
status = y + 2;
$display("child");
endfunction: SetStatus
endclass: myPacket
module top;
Packet pkt = new;
myPacket m_pkt = new;
task my_run (Packet PKT);
PKT.SetStatus(2);
$display("Status value is = %0d", PKT.status);
endtask: my_run
initial begin
my_run(pkt);
my_run(m_pkt);
end
endmodule: top
and this is my output
base
Status value is = 2
base
Status value is = 2
In reply to Deepthip:
Even in the above snippet I am overriding the method SetStatus in child class and the method is non virtual. But the base class method gets called with both parent and child class handles.
But not the same with first case printA method.
In reply to Deepthip:
In your 2nd code, you have the task(my_run) which has the argument of type base class. So, when you call “my_run(m_pkt)”, in fact, you are passing an object of type derived class to a handle of type base class (like Base_handle = Derived_Object). Hence it will still call base class method since it is non-virtual.
In your 1st code, you are directly calling “derived_object.method()”, hence, the derived class method is getting called.
Please use the code tags.
typedef enum {IDLE, RUN, P0, P1} cmd_t;
class Packet;
cmd_t cmd;
int status;
bit [7:0] data [0:255];
function void SetStatus (input int y);
status = y;
$display("base");
endfunction: SetStatus
endclass: Packet
class myPacket extends Packet;
bit errBit;
function bit ShowError();
return(errBit);
endfunction: ShowError
function void SetStatus (input int y);
status = y + 2;
$display("child");
endfunction: SetStatus
endclass: myPacket
module top;
Packet pkt = new;
myPacket m_pkt = new;
task my_run (Packet PKT);
PKT.SetStatus(2);
$display("Status value is = %0d", PKT.status);
endtask: my_run
initial begin
pkt.SetStatus(2);
$display("Status value is = %0d", pkt.status);
m_pkt.SetStatus(2);
$display("Status value is = %0d", m_pkt.status);
my_run(pkt);
my_run(m_pkt);
end
endmodule: top