Welcome to CrankyGoblin.Com Sign in | Join | Help

Public Class GeoffAppleby

Inherits Microsoft.VisualBasic.MVP : Implements IBrainFart
Casting and Overriding

Today I asked myself a question that I've asked myself many times. Today, however, I actually bothered to find out the answer.

Before you jump ahead, let me assure you that no, the question was not 'why do cows look so damn attractive?'.

Nor was it 'when is a duck?'.

It was 'If ClassA has a method Foo, and ClassB inherits ClassA, and ClassB over rides ClassA's foo, and then I create an instance of ClassB and cast it as ClassA, and then call Foo, which Foo runs?'

Stop and think about it. There's only two answers here - either ClassA's, or ClassB's. But there's a pretty strong case for both answers too. If I've cast to ClassA, then only ClassA methods should be called, right? But if ClassB has over ridden ClassA, and while we've cast to ClassA, it's still a ClassB behind the scenes that was instantiated. Oh the conundrum!

So which one is it? I decided it was time to find out - I was expecting the answer to be ClassA's, but I was hoping the answer would be ClassB's. If it was, then I could reduce the amount of code I had to write in a method I was writing by 75% (the method received an object of ClassA, but it was really either ClassB, C, D, or E, all of which inherit A. I needed to call the same method on all of them, but make sure that the over ridden method was called, not the just the base.

Well, here's the test code I whipped up. First I wrote classes A and B.

Public Class ClassA

    Public Overridable Sub Foo()
        Console.WriteLine("-This is A's Foo")
    End Sub

End Class

Public Class ClassB
    Inherits ClassA

    Public Overrides Sub Foo()
        Console.WriteLine("-This is B's Foo")
    End Sub

End Class

Then I write something that calls it.

Module Module1

    Sub Main()

        Dim oA As New ClassA
        Dim oB As New ClassB
        Dim oC As ClassA = CType(oB, ClassA)

        Console.WriteLine("Calling A's Foo")
        oA.Foo()
        Console.WriteLine("Calling B's Foo")
        oB.Foo()
        Console.WriteLine("Calling A's Foo on a B Object")
        oC.Foo()

    End Sub

End Module

And now <insert drumroll here> the results are:

Calling A's Foo
-This is A's Foo
Calling B's Foo
-This is B's Foo
Calling A's Foo on a B Object
-This is B's Foo

Well gosh! I was happy indeed. (I asked four other people at work what they predicted the results to be. Only one person got it right :)

Listening to: all my lovin - me first and the gimme gimmes - (1:54)
Posted: Thursday, March 03, 2005 8:06 PM by Geoff Appleby
Filed under: ,

Comments

MattyT said:

C++ folks should know the answer to this one because it bears a very similar relationship to:

struct A
{
virtual void foo();
};

struct B : public A
{
virtual void foo();
};

///

A * a = new B();
a->foo(); // Calls B::foo

Virtual function selection occurs at runtime - the static type doesn't mean squat. Just like if you changed "struct B" to "class B" B::foo would still be called.

Geez, I sound like a language lawyer tonight! ;)
# March 3, 2005 6:06 PM

TrackBack said:

# March 3, 2005 4:57 AM

TrackBack said:

# March 3, 2005 4:59 AM

Raymond Lewallen said:

Yep that's what I would expect to happen, like Matt said, back from my C++ days. Wanna see something freaky though? Check out the IL for the code you put up. The call for C.Foo() calls virtual method Foo on A, but returns the results for B.

.method public static void Main() cil managed
{
// Code Size: 82 byte(s)
.maxstack 1
.locals (
WindowsApplication1.ClassA sa1,
WindowsApplication1.ClassB sb1,
WindowsApplication1.ClassA sa2)
L_0000: nop
L_0001: newobj instance void WindowsApplication1.ClassA::.ctor()
L_0006: stloc.0
L_0007: newobj instance void WindowsApplication1.ClassB::.ctor()
L_000c: stloc.1
L_000d: ldloc.1
L_000e: stloc.2
L_000f: ldstr "Calling A\'s Foo"
L_0014: call void [mscorlib]System.Console::WriteLine(string)
L_0019: nop
L_001a: ldloc.0
L_001b: callvirt instance void WindowsApplication1.ClassA::Foo()
L_0020: nop
L_0021: ldstr "Calling B\'s Foo"
L_0026: call void [mscorlib]System.Console::WriteLine(string)
L_002b: nop
L_002c: ldloc.1
L_002d: callvirt instance void WindowsApplication1.ClassB::Foo()
L_0032: nop
L_0033: ldstr "Calling A\'s Foo on a B Object"
L_0038: call void [mscorlib]System.Console::WriteLine(string)
L_003d: nop
L_003e: ldloc.2
L_003f: callvirt instance void WindowsApplication1.ClassA::Foo()
L_0044: nop
L_0045: ldstr "Calling A\'s Foo on a B Object"
L_004a: call void [mscorlib]System.Console::WriteLine(string)
L_004f: nop
L_0050: nop
L_0051: ret
}

# March 3, 2005 8:02 PM

Callum said:

It's called Polymorphism! How can you do O-O development and that not be one of the first things you learn?
# March 3, 2005 8:27 PM

Darrell said:

I would have said "B.Foo()" as well. Mostly because that is how polymorphism would seem to logically work and casting should not affect it, not because I'm a language lawyer or anything. :)
# March 3, 2005 9:29 PM

Callum said:

Raymond,

There is a link right at the top (before the questions) which says "Credit here" pointing directly to your blog.

Callum
# March 3, 2005 11:48 PM

Jay Kimble said:

I'm humbled to be in you guys' presence... I missed the logic entirely... I feel enlightened and stupid all at the same time...
# March 14, 2005 10:34 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

To submit your comment, click on these pictures:
  • Searching Geoff
  • Shocked Geoff
  • Geoff's pretty blue eyes
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Can't recognise the people in these pictures? Look here for a quick introduction.
There's a time limit for you to get your comment submitted before this set of pictures expires. If you think it's been longer than 10 minutes, get some new pictures first (you won't lose what you've typed so far).
Get some new pictures 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS