Overriding Virtual Functions

I made this SystemVerilog code
I want to override getArea() method in the derived classes
but It doesn’t seem to work. any explanation?

It says invalid args number.

class Base;
  virtual function int getArea();
  endfunction
endclass


class Rectangle extends Base;
  int width;
  int height;
  function new(int width, int height);
    this.width = width;
    this.height = height;
  endfunction
  virtual function int getArea(int width, int height);
    begin
      return(width*height);
    end
  endfunction
  
endclass

    
class circle extends Base;
  int radius;
  function new(int radius);
    this.radius = radius;
  endfunction
  virtual function int getArea(int radius);
    return(radius*radius*3.14);
  endfunction
 
endclass


  module tb;
    circle c;
    Rectangle rect ;
    initial begin
      c = new (5);
      rect = new (5,6);
    end
  endmodule
  

In reply to haithamx15:

SOLUTION:
METHOD OVERLOADING is not supported in SystemVerilog.

In reply to haithamx15:

I think you are mixing two different concepts. Method overloading would be defining getArea() more than once within the same class with different prototypes. But with virtual method, the prototype is fixed in the Base class. You call a virtual method using a base Base class variable, but you don’t know if the variable hold a handle to the base or extended class object.

In reply to dave_59:

In reply to haithamx15:
I think you are mixing two different concepts. Method overloading would be defining getArea() more than once within the same class with different prototypes. But with virtual method, the prototype is fixed in the Base class. You call a virtual method using a base Base class variable, but you don’t know if the variable hold a handle to the base or extended class object.

Overloading is in the same class understandable!

Dave look at the following code I’ve just coded to understand the concept of Virtual Classes better!


class Base;
  string address;
  function new(string address);
    this.address = address;
  endfunction
  task show();
    $display("BASE CLASS: Address = %0s",address);
  endtask
  
endclass


class Rectangle extends Base;
  string data;

  function new(string address, string data);
        super.new(address);
    this.data = data;

  endfunction
    virtual task show();
      $display("RECTANGLE CLASS: Addr=%0s, data=%0s",this.address,this.data);
  endtask
  
endclass

    
class Circle extends Base;
  string command;
  string data;
  function new(string address, string data, string command);
    super.new(address);
    this.data = data;
    this.command = command;
  endfunction
  
    virtual task show();
      $display("CIRCLE CLASS: Addr=%0s, data=%0s, CMD=%0s",this.address,this.data,this.command);
  endtask
endclass


  module tb;
    Base b;
    Circle c;
    Rectangle r ;
    Circle c2;
    Base ba; //handle to base!
    initial begin
      b = new("Adr: BASE");
      r = new ("Adr: Rect","RectData");
      c = new ("Adr: Circle","CircData","BURST");
      $display("\n \n \n \n ");
      b.show(); //normal call
      r.show(); //normal call
      c.show(); //normal call
      $display("\n \n \n \n ");

      ba = c;
      ba.show();      
     
     $cast(c2,ba);
      c2.show();

    end
  endmodule
  

The output is like this:

BASE CLASS: Address = Adr: BASE
RECTANGLE CLASS: Addr=Adr: Rect, data=RectData
CIRCLE CLASS: Addr=Adr: Circle, data=CircData, CMD=BURST



BASE CLASS: Address = Adr: Circle
CIRCLE CLASS: Addr=Adr: Circle, data=CircData, CMD=BURST

and when modifying the base class and make the show() method virtual this is the output.

BASE CLASS: Address = Adr: BASE
RECTANGLE CLASS: Addr=Adr: Rect, data=RectData
CIRCLE CLASS: Addr=Adr: Circle, data=CircData, CMD=BURST



CIRCLE CLASS: Addr=Adr: Circle, data=CircData, CMD=BURST
CIRCLE CLASS: Addr=Adr: Circle, data=CircData, CMD=BURST

So cast made the it look like as if show() method was virtual, but by making it virtual in the first place it would behave as it should be. Now what we can understand from this?

  1. Virtual Method calls the correct method of the object that the class variable/handle pointing to! (is it determined at compile time or at run time?)

  2. dynamic casting was able to provide us with the same result to use the methods of the correct object/class but that required the programmer to know if that was a valid casting. else it would have returned a null pointer. (All done at runtime)

Dave, please correct me If I’m wrong. And I have another question. I still don’t grasp why would we need cast for? is there a practical example that shows the significance of it? I thoroughly watched your video of OOP and I understood it preciesly but wasn’t able to think of a case where we need it.

By the way, thank you dave for those tutorial videos, they are really professionaland helpful.

In reply to haithamx15:
Dave, please correct me If I’m wrong. And I have another question. I still don’t grasp why would we need cast for? is there a practical example that shows the significance of it? I thoroughly watched your video of OOP and I understood it preciesly but wasn’t able to think of a case where we need it.

A derived class is an extension of base class. So, a base class variable can point to derived class object without any problems. We can’t say the same thing about if we go vice versa. This should not be allowed. But what happens when base class variable actually contains derived class.

BaseC B1 ;
DerivedC D1 ;
BaseC general_class_handle;

D1 = new();
general_class_handle = D1; // this is legal as general_class_variable is of base class type and pointing to derived class object
D1 = general_class_handle; // this is not legal, in the current form, as we are trying to assign a base class object to derived class variable. However, we know that general_class_handle actually points to derived class. Hence casting is needed so that compiler can ascertain

It is very important to note that all this is not necessary if these checks can be done at compile time but it is not. The above assignments are happening at run time. So, additional checks are necessary …

In reply to haithamx15:

The most common place to use $cast is when a function returns an object using a base class type, but you know you have a derived object. Look at the createObj function in the 3rd session of my OOP course. Also look at the uvm_object::clone() method