Aineko
Aineko

Reputation: 107

Base method hiding in C# and Java

I am coming from Java background and currently learning C#. I just had a big surprise regarding (what I perceive as ) a difference in a way that an object accesses methods from base/derived class. Here is what I mean:

In Java if I do something like this

class InheritanceTesting
{
    public void InheritanceOne()
    {
        System.out.println("InheritanceOne");
    }
}

class NewInherit extends InheritanceTesting 
{
    public void InheritanceOne()
    {
        System.out.println("InheritanceTwo");
    } 
 }

then run the following:

 public static void main(String[] args)    {
    InheritanceTesting inh = new NewInherit();
        inh.InheritanceOne();    
 }

I get the result:

InheritanceTwo

If I do exactly the same in C#:

class InheritanceTesting
{
    public void InheritanceOne()
    {
        Console.WriteLine("InheritanceOne");
    }
}

class NewInherit : InheritanceTesting
{
    public new void InheritanceOne()
    {
        Console.WriteLine("InheritanceTwo");
    }
}

Then:

InheritanceTesting inh = new NewInherit();
        inh.InheritanceOne();

result is

InheritanceOne

I remember being taught in Java that "object knows what type it is instantiated to", therefore, no surprises when I call the overridden method. Does this mean that the situation is the opposite in C#? Object only "knows" its declared type? If so, what is the logic/advantage in that? It seems to me that Java treats base classes like interfaces - here is your type and here is your actual implementation. I am new to C# and maybe I am missing something obvious here?

Upvotes: 1

Views: 918

Answers (5)

David Waters
David Waters

Reputation: 12028

A slightly more interesting case is the following

class InheritanceTesting
{
    public void InheritanceOne() 
    // Java equivalent would be
    // public final void InheritanceA()
    {
        Console.WriteLine("InheritanceA - One");
    }


    public virtual void InheritanceB()
    // Java equivalent would be
    // public void InheritanceB() // note the removing of final
    {
        Console.WriteLine("InheritanceB - One");
    }
}

class NewInherit : InheritanceTesting
{
    public new void InheritanceOne() 
    // There is no Java equivalent to this statement
    {
        Console.WriteLine("InheritanceA - Two");
    }


    public override void InheritanceB()
    // Java equivalent would be
    // public void InheritanceB()
    {
        Console.WriteLine("InheritanceB - Two");
    }
}

What you are seeing are some of the difference between C# and Java, you can get C# to behave like Java as the method InheritanceB will show.

C# methods are final by default, so you need to take a positive action to make it possible to override a method by marking it as virtual. So the virtual method InheratanceB will behave like you expect methods to behave, with method dispatch based on the object type, not the reference type. e.g.

 NewInherit example = new NewInherit();
 InheritanceTesting secondReference = example;
 example.InheritanceB();
 secondreference.InheritanceB();

Will both produce InheritanceB - Two as the method InheritanceB was virtual (able to be overriden) and overridden (with the override method).

What you where seeing is called method hiding, where the method can not be overriden (non-virtual) but can be hidden, hidden methods are only hidden when the reference (not the object) is of the derived type so

 NewInherit example = new NewInherit();
 InheritanceTesting secondReference = example;
 example.InheritanceA();
 secondreference.InheritanceA();

Will produce InheritanceB - Two first and InheritanceB - One second. this is because (at least in the simple cases) invocation of final methods is bound at compile time based on the reference type. This has a performance benifit. Binding of virtual methods needs to be differed to runtime as the compiler may not be aware of the instances class.

In practice method hiding is not widely used, and some organisation have coding standards forbidding it. the normal practice is to mark the methods you expect a sub-class to be able to override as virtual and in the sub-class use the keyword override.


More directly answering your questions

Does this mean that the situation is the opposite in C#? Object only "knows" its declared type?

No, c# knows both the constructed type (instance) and the declared type (reference). It uses the instance type for overridden methods and the declared type for final methods even if the instance has hidden the method.

If so, what is the logic/advantage in that?

No the case, I believe there are performance benefits in binding at compile time where possible, e.g. allow in-lining of methods. Also as explained there is not a loss of flexibility as you can have the same behaviour as Java by using the virtual and override keywords.

Upvotes: 4

Mehmet Ataş
Mehmet Ataş

Reputation: 11549

You might think that you have written the same thing (same words), though you did not (you used new keyword in c# version) but C# equivalent of what you wrote in Java is this.

class InheritanceTesting
{
    public virtual void InheritanceOne()
    {
        Console.WriteLine("InheritanceOne");
    }
}

class NewInherit : InheritanceTesting 
{
    public override void InheritanceOne()
    {
        Console.WriteLine("InheritanceTwo");
    } 
 }

In Java, by default all methods, except privates and statics of course, are virtual and any method has same signature with a super class method is an override.

Upvotes: 1

Blindy
Blindy

Reputation: 67380

Java makes methods virtual by default, while in C# you have to explicitly enable virtual inheritance.

That's why you added the new modifier right? Because you got a warning about it? That's because without a method being virtual, you replace it statically if in a derived class you redefine it. If instead of calling InheritanceOne() through a base pointer you call it through a derived pointer you'll get the result you expect -- the compiler chooses non-virtual methods at compile time, based on compile time only information.

TL;DR: Anytime you want to use inheritance for a method, make it virtual in C#. new is one of the worst things in the language for methods, it has no real use and only adds gotchas to your code.

Upvotes: 2

Edward Eisenhart
Edward Eisenhart

Reputation: 390

Java treats methods as virtual by default, C# methods are non-virtual by default. If you want the same behavior in C# use the virtual keyword. In Java you can use final to ensure an inherited class doesn't override a method.

The reason C# methods are not virtual by default is most likely to prevent people from being able to change every inherited functions behavior on the fly in ways the base class designer didn't intend. This gives more control to the base class designer and ensures that inheritance is carefully and willfully planned for rather than just done on the fly.

Upvotes: 2

Pandiri
Pandiri

Reputation: 329

By default, every method in Java can be overridable by its sub classes(unless private/static etc).

In C#, you have to make a method virtual if it has to be overriden by sub classes.

In your C# example, its not a overriden method so the behaviour is expected.

Upvotes: 0

Related Questions