Reader Level:
ARTICLE

Abstract Base Class Polymorphism

Posted by Phil Curnow Articles | Visual C# August 30, 2007
Refactoring the program code from my Polymorphism, Up-casting and Down-casting article to use an abstract base class.
  • 0
  • 0
  • 26352
Download Files:
 

Back in June of this year, I wrote an article titled 'Polymorphism, Up-casting and Down-casting' This article was quite well received and I thank everyone who left comments and emailed me directly about it. For those of you who have not read the article, it presented a Shape base class and then two derived classes Circle and Square, I then went on to explain how to implement polymorphism using these classes, to fully appreciate this current article, it is worth reading the original article.

One question I did receive by email, was asking why I did not implement the base class as abstract. Quite simply, the base class was not implemented as abstract to aid in the explanation of polymorphism. I have put together this short article to demonstrate how to refactor the code from the original article to use an abstract base class and to highlight a couple of areas that need modification in order for an abstract base class to work.

What I will not cover here is exactly what an abstract class is and what you can use it for. I am assuming (always fatal!) that you understand abstract classes. If not, there are many good articles on this site explaining abstract classes.

The original Shape base class:

The original class used as the base (Shape) was coded as follows:

public class Shape
{
    protected int m_xpos;
    protected int m_ypos;

    public Shape()
    {}

 

    public Shape(int x, int y)
    {
        m_xpos = x;
        m_ypos = y;
    }

 

    public virtual void Draw()
    {
        Console.WriteLine("Drawing a SHAPE at {0},{1}", m_xpos, m_ypos);
    }
}

 

To convert this to an abstract class, we would declare the class as abstract. As the behavior of Draw will vary for each derived class, we will also make this abstract, thus ensuring that each derived class implements Draw. Our refactored base class now looks like this (I have emboldened the changes in the new class).

 

abstract public class Shape
{
    protected int m_xpos;
    protected int m_ypos;


    public Shape()
    {}

 

    public Shape(int x, int y)
    {
        m_xpos = x;
        m_ypos = y;
    }

 

    abstract public void Draw();
}

 

That's all the changes we need to make to our base class. Our derived classes need no modification. So basically, that's all there is to it, we need make no modifications to the test code? Well, no not quite. We did have a section of code that demonstrated using the classes non-polymorphically and polymorphically.

 

The non-polymorphic code was as follows:

 

Shape shape1 = new Shape(100, 100);
Circle circle = new Circle(200, 200);
Square square = new Square(300, 300);
shape1.Draw();
circle.Draw();
square.Draw();

 

Now we have implemented Shape as an abstract class, we need to make a couple of changes here. You are not able to create an instance of an abstract class, so we need to remove the two emboldened lines from the code above. Similarly for the polymorphic example, we need to change the code from:

 

Shape[] shapes = new Shape[3];
shapes[0] = new Shape(100, 100);
shapes[1] = new Square(200, 200);
shapes[2] = new Circle(300, 300);
foreach (Shape shape in shapes)
shape.Draw();

 

To...

 

Shape[] shapes = new Shape[2];
shapes[0] = new Square(200, 200);
shapes[1] = new Circle(300, 300);
foreach (Shape shape in shapes)
shape.Draw();

Again, we have reduced the size of the array and removed the code that adds a new instance of Shape to the array. If this was not removed, you would have received the compiler error lioke as follows:

Cannot create an instance of the abstract class or interface 'Polymorphism.Shape'

 

Now that we have made these changes, the test code works correctly.

Conclusion:

As I have said, the original article didn't implement the base class as abstract because of the way I wanted to demonstrate polymorphism. Implementing Shape as an abstract class probably makes more sense if modeling this in what I call the 'real world'. Would we want the ability to be able to create an instance of a Shape? I would argue that we wouldn't, but we do want to be able to create Circles, Squares or any other kind of shape and refer to them as shapes in the way that polymorphism enables us to do.

COMMENT USING

Trending up