google ads

Tuesday, May 19, 2009

Polymorphism and Virtual Functions

A while back I was writing a music system, and I decided that I wanted to be able to support both WinAmp and Windows Media Player as playback engines, but I didn’t want all of my code to have to
know which engine it was using. I therefore defined an abstract class, which is a class that defines the functions a derived class must implement, and that sometimes provides functions that are useful to both classes.
In this case, the abstract class was called MusicServer, and it had functions like
Play(), NextSong(), Pause(), etc. Each of these functions was declared as abstract, so that each player class would have to implement those functions themselves.
Abstract functions are automatically virtual functions, which allow the programmer to use polymorphism to make their code simpler. When there is a virtual function, the programmer can pass around a reference to the abstract class rather than the derived class, and the compiler will write code to call the
appropriate version of the function at runtime.
An example will probably make that clearer. The music system supports both WinAmp and Windows Media Player as playback engines. The following is a basic outline of what the classes look like:

using System;
public abstract class MusicServer
{
public abstract void Play();
}
public class WinAmpServer: MusicServer
{
public override void Play()
{
Console.WriteLine("WinAmpServer.Play()");
}
}
public class MediaServer: MusicServer
{
public override void Play()
{
Console.WriteLine("MediaServer.Play()");
}
}
class Test
{
public static void CallPlay(MusicServer ms)
{
ms.Play();
}
public static void Main()
{
MusicServer ms = new WinAmpServer();
CallPlay(ms);
ms = new MediaServer();
CallPlay(ms);
}
}
This code produces the following output:
WinAmpServer.Play()
MediaServer.Play()
Polymorphism and virtual functions are used in many places in the .NET Runtime system. For example, the base object object has a virtual function called ToString() that is used to convert an object into a string representation of the object. If you call the ToString() function on an object that doesn’t have its own version of ToString(), the version of the ToString() function that’s part of the
object class will be called,[3] which simply returns the name of the class. If you overload—
write your own version of—the ToString() function, that one will be called instead, and you can do something more meaningful, such as writing out the name of the employee contained in the employee object.
In the music system, this meant overloading functions for play, pause, next song, etc.
[3]Or, if there is a base class of the current object, and it defines ToString(), that version will be called.

No comments:

Post a Comment