Virtual functions in C #

public class Base1 { public virtual void f() { Console.WriteLine("Base1.f()"); } } public class Derived1 : Base1 { // Hides Base1.f() because 'override' was not specified public new virtual void f() { Console.WriteLine("Derived1.f()"); } } public class Derived2 : Derived1 { // Overrides Derived1.f() public override void f() { Console.WriteLine("Derived2.f()"); // Call base method base.f(); } } class Program { static void Main(string[] args) Base1 ob1 = new Derived1(); ob1.f(); Base1 ob2 = new Derived2(); ob2.f(); Derived1 ob3 = new Derived2(); ob3.f(); Derived2 ob4 = new Derived2(); ob4.f(); } } // Calls Derived2.f() because Derived2 overrides Derived1().f() Derived1 ob3 = new Derived2(); ob3.f(); 

he expected

 Base1 ob2 = new Derived2(); ob2.f(); 
  • The derived function 2 is called, but the base class function was the reason for this.
  • Does .net use vtables
+4
source share
3 answers

The method slot used by static analysis at compile time depends on the type of variable (or expression), and not the actual object. The variable ob2 is entered as Base1 , therefore, the slot of the Base1 method is Base1 . And then the correct redefinition is selected based on the typed one (essentially vtable in this slot). Therefore, the basic function is used.

To use the derivative2 function, the variable (or expression) must be typed as Derived1 or a subclass.

+6
source

Basically, if the type of compilation time of the variable that you use to call f() is Base1 , it will call the base method, because nothing cancels it.

If the compile-time type is Derived1 or Derived2 , it will call the corresponding method in Derived1 or Derived2 based on the runtime type of the object ... because at this point the compiler will simply issue a virtual call to Derived1.f() , and the override will happen at runtime.

And yes, .NET uses vtables.

+3
source

The problem is that you mix things up too much.

Basically, here is what you did:

  • You define a virtual method f in the base class
  • You drop from this base class and create a new virtual f method
  • You drop from the second class and redefine f , this redefines one from the second class, and not from the base class.

So when you say:

 Base1 b = new Derived2(); bf(); 

then you are always (in this case) going to call the base implementation of f , since the overridden f in Derived2 is another f method. The name is the same, but it is still a different method.

The reason for this is because the compiler will see that the f you are calling is the one that comes from the Base1 class, and therefore it will call that.

Since the class does not override Base1.f , the one you are calling.


In response to a question in a comment, strictly speaking, the class will have two virtual methods, both of which are called f.

One, however, is obscured by the new one introduced in Derived1.

Inside the class, you can choose to call:

 public void MethodInDerived1() { f(); // calls Derived1.f() base.f(); // calls Base1.f() } 

From the outside, however, you need to β€œchoose” by casting.

In other words:

 Derived1 d = new Derived1(); df(); // calls Derived1.f() ((Base1)d).f(); // calls Base1.f() 

You can also observe methods through reflection. If you execute the following code in LINQPad , you will see that there are two methods named f :

 void Main() { typeof(Derived1).GetMethods().Dump(); } public class Base1 { public virtual void f() { Debug.WriteLine("Base1.f"); } } public class Derived1 : Base1 { public virtual new void f() { Debug.WriteLine("Derived1.f"); } } public class Derived2 : Derived1 { public override void f() { Debug.WriteLine("Derived2.f"); base.f(); } } 

The output from this script is truncated (there is more information on the right):

Output from LINQPad script

+3
source

All Articles