Inheritance and Method Overloading

Java overloading and inheritance rules

The behavior of these method calls is dictated and described by the Java Language Specification (reference section 8.4.9).

When a method is invoked (§15.12), the number of actual arguments (and
any explicit type arguments) and the compile-time types of the
arguments are used, at compile time, to determine the signature of the
method that will be invoked (§15.12.2). If the method that is to be
invoked is an instance method, the actual method to be invoked will be
determined at run time, using dynamic method lookup (§15.12.4).

In your example, the Java compiler determines the closest match on the compile type of the instance you are invoking your method on. In this case:

A.method(AX)

The closest method is from type A, with signature A.method(A). At runtime, dynamic dispatch is performed on the actual type of A (which is an instance of AX), and hence this is the method that is actually called:

AX.method(A)

Is method overloading from different classes possible without inheritance? Many sources claim no. But I don't get any error. Why is that so?

Overloading a method in Java is always within a class, not from different classes

You won't get any error as is allowed what you have done

Method overloading and inheritance

Basically, the way method invocation works in C# is that the compiler looks at the most derived class first, and sees whether any newly declared methods (not including overrides) are applicable for the arguments for the call. If there's at least one applicable method, overload resolution works out which is the best one. If there isn't, it tries the base class, and so on.

I agree this is surprising - it's an attempt to counter the "brittle base class" issue, but I would personally prefer that any overridden methods were included in the candidate set.

Method invocation is described in section 7.6.5.1 of the C# 5 specification. The relevant parts here is:

  • The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)

And in the member lookup part of 7.4, override methods are explicitly removed:

Members that include an override modifier are excluded from the set.

C# method overload with inheritance

If you want to have really dynamic resolution, then you have to use dynamic keyword, like so:

static void Main(string[] args)
{
dynamic ship = new SpaceShip();
Planet planet = new Planet();

ship.Visit(planet); // => Specific

// also
GenericPlanet genericPlanet = new GenericPlanet();
ship.Visit(planet); // Generic
}

In this case behaviour will be something like you have described - type of the parameter matters. But what you most likely want is to have a method override, like so:

class GenericSpaceShip
{
public virtual void Visit(GenericPlanet planet)
{
Console.WriteLine("Generic");
}
}

class SpaceShip : GenericSpaceShip
{
public override void Visit(GenericPlanet planet)
{
Console.WriteLine("Specific");
}
}

In this case the Specific method will be called if you have an instance of SpaceShip and Generic method for instance of GenericSpaceShip, regardless of planet type. In this case type of the ship matters:

static void Main(string[] args)
{
SpaceShip ship = new SpaceShip();
Planet planet = new Planet();

ship.Visit(planet); // => Specific

// also
GenericPlanet genericPlanet = new GenericPlanet();
ship.Visit(planet); // Specific
}

You would always get Generic if GenericSpaceShip was used instead.

Method overloading & inheritance - how to address to the right method?

Overload Resolution happens at compile time. The C# compiler uses the static type of an argument to find the best overload. Since you are calling the method with an argument of type Child, the compiler does not find a matching overload. None of the three overloads has a parameter of type Child. There is no implicit conversion from Child to BoyChild, GirlChild or UndecidedChild. You can assign a derived class to a base class, but not the other way around.

The way to go, is to use polymorphy, i.e., to add an abstract Validate method to the (abstract) Child class (unless you can provide a standard implementation in the base class). The derived classes then must override this method and provide an implementation. At runtime, Dynamic dispatch will then call the right implementation.



Related Topics



Leave a reply



Submit