Calling the overridden method from the base class in C#

30,779

Solution 1

Which method is called is determined via polymorphism on the type that is passed into the AnotherObject constructor:

AnotherObject a = new AnotherObject(new A()); // invokes A.MyMethod() 
AnotherObject b = new AnotherObject(new B()); // invokes B.MyMethod() 
AnotherObject c = new AnotherObject(new BaseClass()); //invokes BaseClass.MyMethod() 

Solution 2

Sorry, but you are completely mistaken; this would go against the entire point of virtual methods. If someObject is an A then A.MyMethod will be invoked. If someObject is a B then B.MyMethod will be invoked. If someObject is a BaseClass and not an instance of a type derived from BaseClass then BaseClass.MyMethod will be invoked.

Let's use everyone's favorite example:

class Animal {
    public virtual void Speak() {
        Console.WriteLine("i can haz cheezburger?");
    } 
}
class Feeder {
    public void Feed(Animal animal) { animal.Speak(); }
}
class Cat : Animal {
    public override void Speak() { Console.WriteLine("Meow!"); }
}
class Dog : Animal {
    public override void Speak() { Console.WriteLine("Woof!"); }
}

Then:

Animal a = new Animal();
Animal c = new Cat();
Animal d = new Dog();
Feeder f = new Feeder();
f.Feed(a);
f.Feed(c);
f.Feed(d);

This will print:

i can haz cheezburger?
Meow!
Woof!

Again, this is the entire point of virtual methods.

Further, we can go to the specification. From 10.6.3 (Virtual methods)

In a virtual method invocation, the run-time type of the instance for which that invocation takes place determines the actual method implementation to invoke.

(Bolding and italics in original.)

In precise terms, when a method named N is invoked with an argument list A on an instance with a compile-time type C and a run-time type R (where R is either C or a class derived from C), the invocation is processed as follows:

• First, overload resolution is applied to C, N, and A, to select a specific method M from the set of methods declared in and inherited by C. This is described in §7.5.5.1.

• Then, if M is a non-virtual method, M is invoked.

Otherwise, M is a virtual method, and the most derived implementation of M with respect to R is invoked.

(Bolding not in original.)

Then, we need the definition of "most derived implementation of M." This is a nice recursive definition:

The most derived implementation of a virtual method M with respect to a class R is determined as follows:

• If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.

• Otherwise, if R contains an override of M, then this is the most derived implementation of M.

• Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.

Thus, in our example above with Cat : Animal and Dog : Animal, when the parameter a to Feeder.Feed(Animal) is an instance of Cat then Cat.Speak is the most derived implementation. This is why we will see "Meow!" and not "i can haz cheezburger?"

Solution 3

If MyMethod() is abstract on the base class, then the version in the derived classes will be used. So if you don't need to call the instance in the base class, this would be an option.

    static void Main(string[] args)
    {

        A classA = new A();
        B classB = new B();

        DoFunctionInClass(classA);
        DoFunctionInClass(classB);
        DoFunctionInClass(classA as BaseClass);

        Console.ReadKey();
    }

    public static void DoFunctionInClass(BaseClass c) 
    {
        c.MyMethod();
    }



public abstract class BaseClass
{
    public abstract void MyMethod();
}


public class A : BaseClass
{
    public override void MyMethod()
    {
        Console.WriteLine("Class A");
    }
}

public class B : BaseClass
{
    public override void MyMethod()
    {
        Console.WriteLine("Class B");
    }
}

Solution 4

If someObject passed in is class A, then A.MyMethod is called, not the base class implementation. Also look at the is keyword.

Solution 5

Because you've typed it as a BaseClass instead of an A or a B, the baseclass is the begin point for the method calls.

You might try using a generic:

public class AnotherObject 
{ 
    public AnotherObject<T>(T someObject) where T : BaseClass
    { 
        someObject.MyMethod(); //This calls the BaseClass method, unfortunately. 
    } 
} 

I'm not sure how well this will fly in the constructor, but you might be able to move this to a different method.

Share:
30,779

Related videos on Youtube

David
Author by

David

Biomedical engineer and neuroscientist

Updated on July 09, 2022

Comments

  • David
    David almost 2 years

    Given the following C# class definitions and code:

    
    public class BaseClass
    {
        public virtual void MyMethod()
        {
            ...do something...
        }
    }
    
    public class A : BaseClass
    {
        public override void MyMethod()
        {
            ...do something different...
        }
    }
    
    public class B : BaseClass
    {
        public override void MyMethod()
        {
            ...do something different...
        }
    }
    
    public class AnotherObject
    {
        public AnotherObject(BaseClass someObject)
        {
            someObject.MyMethod(); //This calls the BaseClass method, unfortunately.
        }
    }
    

    I would like to call the MyMethod() that is actually found in A or B, assuming the object passed in is actually an instance of A or B, not that which is found in BaseClass. Short of doing something like this:

    
    public class AnotherObject
    {
        public AnotherObject(BaseClass someObject)
        {
            A temp1 = someObject as A;
            if (A != null)
            {
                A.MyMethod();
            }
            
            B temp2 = someObject as B;
            if (B != null)
            {
                B.MyMethod();
            }
        }
    }
    

    How can I do it?

    • Nick
      Nick about 14 years
      What is the type of the ACTUAL object you are passing in to the AnotherObject constructor? In other words, what is the new statement? Because what you are describing can only happen if you new a BaseClass instead of an A or a B.
    • David
      David about 14 years
      Oops. Just realized my problem. One of the several classes I thought was overriding the function was actually failing to override the function. Problem solved.
    • Greg
      Greg about 14 years
      I think the fact that it's a code smell is obvious to David otherwise the question wouldn't have been posted and the smelly code would have been used instead.
  • Yuriy Faktorovich
    Yuriy Faktorovich about 14 years
    I must have missed the class where the Feeder was involved. With me it is very likely.
  • Yuriy Faktorovich
    Yuriy Faktorovich about 14 years
    Use @base. I don't like typing more characters.
  • jason
    jason about 14 years
    @Yuriy Faktorovich: Feeder is just playing the role of the OP's AnotherObject.
  • Greg
    Greg about 14 years
    +1 should consider a design where BaseClass is abstract if the listed behavior is not desired.