I was trying to override a method in SystemVerilog. However I learnt that SystemVerilog does not support C++ style function overloading. Then I resorted to polymorphism where I redefined the method with fewer arguments in the child class. I was successful in compiling and running this method from the child handle.
class parent;
task my_task(input a,input b);
....
endtask
endclass
class child extends parent;
task my_task(input a); //Note I take only one argument here
endtask
endclass
However, problem arose when I try to make the method in the parent class virtual for the testbench to pick the correct method during run time. The compiler throws an error.
class parent;
virtual task my_task(input a,input b);
....
endtask
endclass
class child extends parent;
task my_task(input a); //Throws an error here
endtask
endclass
When I checked the LRM it states :- Virtual method overrides in subclasses shall have matching argument types, identical argument names,
identical qualifiers, and identical directions to the prototype.
So I understand that the child class method arguments should match parent class method arguments. But unless I change the method’s name or not make it virtual in the parent class, I cant seem to override the method.
Is there a better method than renaming methods to overload methods in SystemVerilog ?
Creating another function with a different name is the best way to handle function overloading.
Dynamic polymorphism with virtual methods is a separate concept from static function overloading. With virtual methods you dynamically select at run-time a virtual method based on the handle type of the object stored in a base class variable. If you have
parent p;
...
p.my_task(1);
Even if SystemVerilog did support function overloading, it would be illegal to write p.my_task(1,2) because you don’t know if p contains a handle to a parent object or child object. And if p has a parent object, there is no definition of my_task with two arguments.
C++ is really creating a method with a different name for you by implicitly name mangling the declared method name with its prototype at compile time. SystemVerilog requires you to explicitly name your methods.
I didnt know that C++ does some name adjustment under the hood.
As an extension of the question regarding methods, what if the it were to be a constraint (as in randomization) ? If I am not wrong, I cannot use a ‘virtual’ with a constraint I suppose for run time resolution of which constraint to use ?
class parent_rand;
rand int a;
constraint {a < 10;}
endclass
class child_rand extends parent_rand;
rand int a;
constraint {a > 10;}
endclass
module tb;
parent_rand parent_rand_handle;
child_rand child_rand_handle;
initial
begin
parent_rand_handle = child_rand_handle;
parent_rand_hanlde.randomize(); //What would 'a' end up as here ?
end
endmodule
Aside from the syntax error that the constraints must be named, both parent_rand::a and child_rand::a will be randomized with values greater than 10. You can’t override a class property, so both are allocated when constructing a child_rand object.
See section 18.5.2 Constraint inheritance of the 1800-2012 LRM
The randomize() method is virtual and honors constraints of the object on which it was called.
Any constraint in a derived class having the same name as a constraint in its superclass shall replace the inherited constraint of that name. Any constraint in a derived class that does not have the same name as a constraint in the superclass shall be an additional
constraint.
It is a really bad programming practice to give class properties in an extended class the same name as class properties in its base class.
I tried runnning this piece of code on Questa-64 10.1b
module constr_test();
class parent;
rand int unsigned a;
constraint c1{
(a < 10);
}
endclass
class child extends parent;
rand int unsigned a;
constraint c2{
(a > 10);
}
endclass
parent parent_handle;
child child_handle = new();
initial
begin
parent_handle = child_handle;
parent_handle.randomize();
$display("a = %d",parent_handle.a);
end
endmodule
As per the LRM, I am supposed to get a value > 10 for a(as the constraint in the child class overrides the inherited constraint). But I end up getting a value < 10 for a which is in line with the constraint defined in the parent class.
I probably see what is wrong. But considering that only a child_handle calls a new() and memory is created only for the child_handle which is then passed onto parent_handle, how is it that there are different parent_handle.a and child_handle.a variables even though I didnt create a parent_handle object?
Your use of the term “parent” and “child” for classes with inheritance is misleading. When you extend a class , then construct it, the two classes become one. Better terms are “base” and derived" classes. When you construct a “derived” class, you are constructing everything in the base as well.
Yes but isn’t the value of ‘a’ mutually exclusive ? I don’t understand why 2 a’s are created when I have constructed only one object which happens to be the derived class. And that value in the derived class overrides inherited value as per the LRM.
When you say “2 classes become one” shouldn’t the value in the derived class override the value inherited from base class ?
Yes but isn’t the value of ‘a’ mutually exclusive ? I don’t understand why 2 a’s are created when I have constructed only one object which happens to be the derived class. And that value in the derived class overrides inherited value as per the LRM.
When you say “2 classes become one” shouldn’t the value in the derived class override the value inherited from base class ?
Constraint blocks are virtual, meaning when the constraint block in derived class has the same name as parent class, it would get override. I have modified the code, which works for your requirement !!
module polym_cons();
class parent;
rand int unsigned a;
constraint c1{
(a < 10);
}
endclass
class child extends parent;
constraint c1{
(a > 10);
}
endclass
parent parent_handle;
child child_handle = new();
initial
begin
parent_handle = child_handle;
parent_handle.randomize();
$display("a = %d",parent_handle.a);
end
class A;
int a=10;
function void disp();
$display("a=%d",a);
endfunction
endclass
class B extends class A;
int a=20;
endclass
program main();
A a;
B b;
b =new();
b.disp(); //diplays a=10
$display("b.a=%d",b.a); // displays a=20
endprogram
My questions is, now b has two a’s and a disp() function. How does simulator know which value of a to display when I call b.disp() ?? what is the OOP concept governing this situation?
2nd question: How can I access a of base class with derived class handle in program block?
Hi,
When your creating an object of the derived class the simulator adds super.new() constructor and allocates memory for the base class as the derived class is inherited.Hence there will be base class ‘a’ and derived class ‘a’ being created(name hiding).
As per the LRM only virtual methods can be overriden.
class A;
int member1;
endclass
class A1 extends A;
int member2;
endclass
class A2 extends A;
int member3;
endclass
A1 a1_h = new();
A2 a2_h;
// this is not legal
a2_h = a1_h;
There no cast that would make it legal. a2_h.member3 does not exit in the constructed object.
class A;
int a=10;
virtual function void disp();
$display("Base a=%d",a);
endfunction
endclass
class B extends A;
int a=20;
function void disp();
$display("Derived a=%d",a);
endfunction
endclass
module tb();
A a=new;
B b;
initial begin
$cast(b,a);
b.disp(); //
$display("b.a=%d",b.a); //
a.disp(); //
$display("a.a=%d",a.a); //
end
endmodule
I have a compilation error when I do a $cast(b,a) without doing “a=b”. Why is that? Then what is the point having $cast?
Error-[DCF] Dynamic cast failed
testbench.sv, 25
Casting of source class type ‘A’ to destination class type ‘B’ failed due to
type mismatch.
Please ensure matching types for dynamic cast
You code comment say you have a run-time error, but your text says you have a compilation error. Also, you seem to be missing an
initial begin/end block. Please correct your post because it really matters to the question you are trying to ask.