Should this type of method overload work in C#?

G

Guest

public class Base
{
}

public class Derived : Base
{
}

public class Service
{
public void Send(Base baseObject)
{
// send baseObject
Console.Out.WriteLine("Called public void Send(Base baseObject)
signature");
}

public void Send(Subclass derivedObject)
{
// send derivedObject
Console.Out.WriteLine("Called public void Send(Subclass derivedObject)
signature");
}
}

public class MainClass
{
public static void Main(string[] args)
{
Base baseObject = new Base();
Derived derivedObject = new Derived();

Service service = new Service();

// this calls public void Send(Base baseObject) as expected
service.Send(baseObject);

// this calls public void Send(Base baseObject),
// but it should call public void Send(Subclass derivedObject),
// shouldn't it???
service.Send(derivedObject);
}
}

I expect this to work, but I tested it at runtime, verifying that the
instance is of the Derived class and it still calls the signature with the
base class.

thanks,

Dave Raskin
 
F

Flip

Howdy. I believe I got it to work properly (as you expected) for me.
Here's the code I used (slightly modified to get it to compile). Output at
the end.
//--------------------------------------------------------------start code
using System;

public class Base
{
}

public class Derived : Base
{
}

public class Service
{
public void Send(Base baseObject)
{
// send baseObject
Console.WriteLine("Called public void Send(Base baseObject) signature");
}

public void Send(Derived derivedObject)
{
// send derivedObject
Console.WriteLine("Called public void Send(Subclass derivedObject)
signature");
}
}

public class MainClass
{
public static void Main(string[] args)
{
Base baseObject = new Base();
Derived derivedObject = new Derived();

Service service = new Service();

// this calls public void Send(Base baseObject) as expected
service.Send(baseObject);

// this calls public void Send(Base baseObject),
// but it should call public void Send(Subclass derivedObject),
// shouldn't it???
service.Send(derivedObject);
}
}
//--------------------------------------------------------------end code


And here's the output I see.

C:\temp>basetesting
Called public void Send(Base baseObject) signature
Called public void Send(Subclass derivedObject) signature

C:\temp>
 
J

Joe Mayo

Hi Dave,

Service doesn't have an overload with a Derived parameter, so the compiler
used a best match that took the overload with the Base parameter. From the
information you've given, I can't tell what SubClass is. However, if you
change the definition of Send(SubClass derivedObject) to this, you could get
what you expect:

public void Send(Derived derivedObject)
{
// send derivedObject
Console.Out.WriteLine("Called public void Send(Derived derivedObject)
signature");
}

Joe
 
G

Guest

You're right, the second Send() signautre should have Derived as param, not
Subclass.

Thanks for your answer. My case didn't work, although what I presented here
is a simplified situation, which I thought was essentially the same, but may
be I missed something. I will take a look.
 
G

Guest

The signature with Subclass should be with Derived, sorry.

Joe Mayo said:
Hi Dave,

Service doesn't have an overload with a Derived parameter, so the compiler
used a best match that took the overload with the Base parameter. From the
information you've given, I can't tell what SubClass is. However, if you
change the definition of Send(SubClass derivedObject) to this, you could get
what you expect:

public void Send(Derived derivedObject)
{
// send derivedObject
Console.Out.WriteLine("Called public void Send(Derived derivedObject)
signature");
}

Joe
--
http://www.csharp-station.com

Dave Raskin said:
public class Base
{
}

public class Derived : Base
{
}

public class Service
{
public void Send(Base baseObject)
{
// send baseObject
Console.Out.WriteLine("Called public void Send(Base baseObject)
signature");
}

public void Send(Subclass derivedObject)
{
// send derivedObject
Console.Out.WriteLine("Called public void Send(Subclass derivedObject)
signature");
}
}

public class MainClass
{
public static void Main(string[] args)
{
Base baseObject = new Base();
Derived derivedObject = new Derived();

Service service = new Service();

// this calls public void Send(Base baseObject) as expected
service.Send(baseObject);

// this calls public void Send(Base baseObject),
// but it should call public void Send(Subclass derivedObject),
// shouldn't it???
service.Send(derivedObject);
}
}

I expect this to work, but I tested it at runtime, verifying that the
instance is of the Derived class and it still calls the signature with the
base class.

thanks,

Dave Raskin
 
G

Guest

Ok, here's an example of where it fails. This has an added wrinkle of another
virtual method - Process().

public abstract class Base
{
protected Service service = new Service();

public abstract void Process();
}

public class BaseDerived : Base
{
public override void Process()
{
this.service.Send(this);
}
}

public class DerivedDerived : BaseDerived
{
}

public class Service
{
public void Send(Base baseObject)
{
// send baseObject
Console.Out.WriteLine("Called public void Send(Base baseObject)
signature");
}

public void Send(DerivedDerived derivedObject)
{
// send derivedObject
Console.Out.WriteLine("Called public void Send(DerivedDerived
derivedObject) signature");
}
}

public class MainClass
{
public static void Main(string[] args)
{
BaseDerived baseObject = new BaseDerived();
DerivedDerived derivedObject = new DerivedDerived();

Service service = new Service();

// this calls public void Send(Base baseObject) as expected
baseObject.Process();

// this calls public void Send(Base baseObject),
// but it should call public void Send(Subclass derivedObject),
// shouldn't it???
derivedObject.Process();
}
}
 
J

Jon Skeet [C# MVP]

Dave Raskin said:
Ok, here's an example of where it fails. This has an added wrinkle of another
virtual method - Process().

<snip>

Overload resolution is done at compile time - it works out the
*signature* of which method will be called. Now, the Process method is
calling

this.service.Send(this)

and all it knows about "this" is that it's a BaseDerived - so it
doesn't know it can call Send(DerivedDerived).
 
B

Bruce Wood

Jon is right.

Here's a simpler method to demonstrate the same phenomenon:

public class Base { ... }
public class Derived : Base { ... }
public class Main
{
private void Print(Base b) { Console.Writeline("Base"); }
private void Print(Derived d) { Console.Writeline("Derived"); }

public static void Main(string[] argv)
{
Derived d = new Derived();
Print(d); // Prints "Derived"
Print((Base)d); // Prints "Base", even though d is an instance
of Derived
}
}
 
G

Guest

Hmm, ok. is true in Java as well? It still seems like it should resolve it at
runtime, but I am not a compiler guy, so what do I know?

Thanks for the clarification!

daver
 
G

Guest

Bruce,

This seems like a flip of my example. Here you have a Derived type at
compile time and explicitely casting to the Base type. In my case, at compile
time it only knows about the Base type.

daver
 
B

Bruce Wood

Yes, but it illustrates the same thing: the run-time type of the
instantiated object isn't what determines which method signature to
call. The compiler decides which method signature to invoke.
 
B

Bruce Wood

Yes, Java is the same. I believe that C++ is also the same.

The rule goes liket his:

The method signature is determined at compile time. That is, if a
method has several different versions with different parameter lists,
the compile-type type of the value passed to the method determines the
signature chosen.

The method overload is determined at run time. That is, if a particular
signature of a particular method is overloaded in a child class, then
whether the base class method or the child class method is to be called
is determined at run time.

(So, just because the compiler determines the signature to call,
_doesn't_ mean that it has decided whether to call the base or derived
implementation of that method. If the derived class overloads the
method, then the choice between the two methods is made at run time.
 
B

Bruce Wood

Rats. I screwed up the use of the term "overload" again. :(

Overload resolution is done at compile time: "overload" refers to
methods with the same name but different signatures.

Override resolution is done at run time: "override" refers to methods
with the same name and the same signature defined at different levels
of the class hierarchy.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top