Overriding Class properties

Hi All,
Consider the following code ::

class base;
  int a = 10;
  
  virtual function void A();
    $display("a is %0d",a);
  endfunction  
  
endclass

class ext extends base;
  int a = 20;
 
`ifdef OVER                   
  virtual function void A();  // Explicitly override the virtual function
    $display("a is %0d",a);
  endfunction  
`endif
  
endclass

module tb;
  
  base   base_h ;
  ext    ext_h ; 
  
  initial  begin
    ext_h  = new();
    base_h = ext_h;    
    base_h.A();   
  end  

endmodule  

My understanding is that objects of class ext have 2 properties named ‘a’
(1) In absence of +define+OVER i.e user doesn’t override the virtual function
I observe o/p as :: a is 10

(2) In presence of +define+OVER i.e user does override the virtual function
I observe o/p as :: a is 20

I am not a 100% clear on the reason behind the observed output and would like to hear from forum

(Q1) For (a) wouldn’t class ext inherit the virtual function by default ?
If yes, then what’s the difference b/w (a) & (b) ?

(Q2) Does scope visibility of property ‘a’ play any part in the output ?

By (a) and (b), I think you meant (1) and (2).

Even though class ext inherits the function base::A(), it is still defined in the base class. All references to identifiers are with respect to the base class.

Yes, a typo from my end

For (2), why is it that we observe a is 20 ?
Handle of base class has no access / knowledge of the overridden property ‘a’ within the extended class ext

On re-defining the 2 functions to

// Within class base
  virtual function void A();
    $display("Within base::A(), a is %0d",this.a);
 endfunction  

// Within class ext
`ifdef OVER                   
  virtual function void A();  // Explicitly override the virtual function
    $display("Within ext::A(),a is %0d",this.a);
  endfunction  
`endif

I observe that for (1) :: Within base::A(), a is 10 for (2) :: Within ext::A(), a is 20

Since the function is virtual by default, I believe the inherited function would be virtual as well
Shouldn’t the ext::A() be called for both (1) and (2) ? (using the concept of polymorphism)

ext::A() only exists in example (2).

The choice of which virtual function gets called is polymorphic. However, once you’re inside the function, there’s no polymorphism (unless that function calls another virtual method). base::A() always references base::a and ext::A() always references ext::a

Hi Dave,
(A) Can I say that “there exists a subtle difference between inheriting a virtual function v/s overriding the virtual function” ?

1. Unless the virtual function is manually overridden, base_h.A() would call the function ‘A’ defined in base class (although the virtual function is inherited by ext class)

2. When user overrides the virtual function, as the overridden property is the nearest in scope
we observe a is 20

(B) Are both of the above pts correct ?

Inheritance doesn’t alter the definition of a base class member(method or property); it simply allows its visibility in extended class types.

When you reference a class property (or a non-virtual method) within a function, the compiler searches for its definition in the current class scope. If the property is not found in the current class, the compiler checks the class it was extended from, and so on, down the chain of base classes. If the property is not found in any class, the compiler uses the Verilog search rules to look in the current package or module hierarchy.

The only difference when a virtual method is called is that the class type of the object instance is used to initiate the search, rather than the compilation scope of where the reference resides.

Thanks, Dave, for the detailed explanation. Using your following comments

Hence in absence of +define+OVER, although the virtual function is inherited the call to base_h.A(); ends up calling base::A()

As the inherited property ‘a’ is nearest in scope (even though the object type is of extended class) to base::A() we observe a is 10

Only when user explicitly overrides the virtual function (+define+OVER), ext::A() exists !!

Now the call to base_h.A(); ends up calling ext::A()

Since the overridden property ‘a’ is nearest in scope to ext::A() we observe a is 20

Please correct me if I am wrong

Thanks