
-----------------------------------
wtd
Sun Dec 17, 2006 4:52 pm

Virtual Methods
-----------------------------------
Virtual Methods?  What the ...?!

Well, this tutorial aims to answer exactly that question.  First, though, we must cover a bit of type theory as it applies to object-oriented programming.

If you're reading this, then I'm assuming you have at least some understanding of the is-a relationship between classes.  This relationship can be created through implementation or interface inheritance.

Java:

class Foo { }

interface Bar { }

class Baz extends Foo implements Bar { }

Now, the class Baz is a Foo object, and it is a Bar object.

So we can do things like:

Java:

Foo a = new Foo();
Foo b = new Baz();
Baz c = new Baz();
Bar d = new Baz();

These all work because of the is-a relationship.

Let's add some methods.

Java:

class Foo { 
    public String getName() {
        return "Foo";
    }
}

class Bar extends Foo { 
    public String getName() {
	    return "Bar";
	}
}

And now we can do the following.

Java:

Foo a = new Bar();

System.out.println("a's name is " + a.getName());

This works because getName is a method in the Foo class.  So the compiler sees no reason to complain.

What's interesting is the actual output.

a's name is Bar

Didn't we tell the compiler that the variable "a" is a Foo object?  And doesn't Foo's getName method return "Foo"?

Yes, we did, and yes it does.  But the actual method lookup occurs at runtime.  As a result, the getName method specified in the Bar class is called.

Let's talk through this a bit more

When I said the "a" variable is of type Foo, I specified that it was allowed to be assigned any value belonging to that class.  Bar objects belong to the class Foo, since they must implement at the very least the functionality present in the Foo class specification.

But the behavior of Java (and numerous other object-oriented programming languages) is not to view this as a directive to strictly interpret "a" as a Foo object.

Since this is the only behavior in so many languages, it's easy to take it for granted.  There just isn't that much thought about it.

Well, not that much thought about it until one hits a language where that's not the case, and some of those languages sit at the top of their game in terms of people using them:  C++, C#, and Object Pascal (Delphi).

By default, they do just the opposite of what we achieved earlier.

Some more code

C++:

class Foo
{
    public:
        std::string get_name() const
        {
            return "Foo";   
        }
};

class Bar : public Foo
{
    public:
        std::string get_name() const
        {
            return "Bar";   
        }
};

Foo *a = new Bar;

std::cout 