Skip to content
wannacode

Abstract classes

Problem

Zero square meters

You are writing a program that orders tiles for a terrace. The terrace has three parts: a 4 × 3 m rectangle, a round part with a radius of 1 m, and a triangle with a base of 2 m and a height of 3 m. There is a parent Shape with Area(), which returns 0, and each shape overrides it.

The colleague who wrote Triangle forgot:

class Triangle : Shape
{
public double Base { get; private set; }
public double Height { get; private set; }
public Triangle(double baseLength, double height)
{
Base = baseLength;
Height = height;
}
}
Shape[] terrace = { new Rectangle(4, 3), new Circle(1), new Triangle(2, 3) };
double total = 0;
foreach (Shape s in terrace)
{
total += s.Area();
}
Console.WriteLine($"Tiles: {total:F2} m²");
Output
Tiles: 15.14 m²

You need 18.14 m². The program gives no error, and the order is 3 m² short. The parent's zero has hidden the missing method.

And what is new Shape()? A shape with no shape. An object like that has no reason to exist.

The idea

Abstract class: a promise the child classes keep

Shape is not a real shape. All it says is "every shape has an area". So make it abstract:

abstract class Shape
{
public abstract double Area();
}
  • An abstract method has no body, only a header and ;. You cannot give a sensible area to "a shape in general", so you give none.
  • An abstract class cannot have objects: new Shape() does not compile.
  • Every child class has to write the method. Otherwise the program does not compile.

Now the forgotten Triangle gives an error at compile time:

"'Triangle' does not implement inherited abstract member 'Shape.Area()'". The child class writes the method with override, just as with virtual.

An error the compiler catches is better than an error in the order.
More precisely, if you are curious
  • A child class that does not write the abstract method can be abstract too. Then the promise passes on to its own child classes.
  • A class can be abstract without a single abstract method. That way you only forbid objects of it.

See it

The triangle keeps the promise

Add the method to Triangle:

class Triangle : Shape
{
// ... Base, Height and the constructor
public override double Area()
{
return Base * Height / 2;
}
}
Shape[] terrace = { new Rectangle(4, 3), new Circle(1), new Triangle(2, 3) };
double total = 0;
foreach (Shape s in terrace)
{
total += s.Area();
}
Console.WriteLine($"Tiles: {total:F2} m²");
Output
Tiles: 18.14 m²

The loop is the same. The Shape[] array holds shapes of three classes, and s.Area() calls the method of each one. The polymorphism from the last lesson works with an abstract parent too.

Try it

Find the bug

Only one line does not compile. Which one?

Pick the line with the bug.

The idea

Abstract, but not empty

An abstract class can have everything an ordinary one has: fields, a constructor, ordinary methods. Let every shape have a name and a method that describes it:

abstract class Shape
{
public string Name { get; private set; }
public Shape(string name)
{
Name = name;
}
public abstract double Area();
public string Describe()
{
return $"{Name}: {Area():F2} m²";
}
}

Describe() is written once, in Shape. It calls Area(), which Shape does not have yet. That is not a problem: Describe() is always called on a real shape, and a real shape has an area.

You do not make objects from Shape, but its constructor is useful: the child classes call it.

class Circle : Shape
{
public double Radius { get; private set; }
public Circle(double radius) : base("circle")
{
Radius = radius;
}
// ... Area() as before
}
Shape[] terrace = { new Rectangle(4, 3), new Circle(1), new Triangle(2, 3) };
foreach (Shape s in terrace)
{
Console.WriteLine(s.Describe());
}
Output
rectangle: 12.00 m²
circle: 3.14 m²
triangle: 3.00 m²

The parent writes what is shared (the name, the description), and the child classes write what is different (the area).

public abstract double Area();
public string Describe()
{
return $"{Name}: {Area():F2} m²";
}
Shape s = new Circle(1);
Console.WriteLine(s.Describe());
Step by step, in words
  1. Shape promises Area() but has no body. There can be no object that is only a Shape.
  2. The object is a circle: the Circle part has its own Area(). It keeps the promise.
  3. s.Describe() is written in Shape and works for every shape.
  4. It calls Area(). The object is a circle, so the Circle method runs: π · 1 · 1.
  5. Describe() puts the text together. What is shared lives in the parent, what differs lives in the child class.
  6. The output is the area of the circle, with two digits after the decimal point.

Try it

Whose method?

What will the program print?

// Shape and Circle are from the card above
Shape s = new Circle(2);
Console.WriteLine(s.Describe());
Answer

Try it

What is missing?

What has to go in the blank so that you cannot create an object of Shape?

 class Shape
{
    public abstract double Area();
}

Exercise

Shapes and animals

Solve the tasks in your editor.

1. Area and perimeter. An abstract class Shape with a name and two abstract methods: Area() and Perimeter(). Child classes Circle (radius) and Rectangle (width and height). Put a circle with a radius of 5 and a 4 × 2.5 rectangle in an array and print both values with two digits after the decimal point.

Output
Circle: area 78.54, perimeter 31.42
Rectangle: area 10.00, perimeter 13.00

2. Animals. An abstract class Animal with an abstract method Sound() and an ordinary method Breathe() that prints "The animal breathes." Child classes Cat and Dog. Call the sound of both in a loop, then Breathe() on the first one.

Output
Meow, meow!
Woof, woof!
The animal breathes.

Exercise

Vehicles and performances

3. Vehicles. An abstract class Vehicle with an abstract method Move(). SimpleCar and Bicycle inherit from it. Bicycle also has its own method Pedal().

Output
The car sets off
The bicycle sets off
Pedaling
Try garage[1].Pedal(). Why does it not compile, even though there is a bicycle there?

4. Performances. An abstract class Performance with a title and an abstract method Start(). DanceMove and Song inherit from it. Song also has a method Sing().

Output
Starting the dance moonwalk
Starting the song 'Bohemian Rhapsody'
Singing 'Bohemian Rhapsody'

More tasks

  • Triangle. Add Triangle with its three sides to task 1. The perimeter is their sum, and the area comes from Heron's formula: s = perimeter / 2, area = √(s(s − a)(s − b)(s − c)). For sides 3, 4 and 5 the area is 6.00 and the perimeter is 12.00.
  • Abstract employee. Make Employee from the last lesson abstract, with an abstract MonthlyPay(). Add FullTime (the salary is paid in full) and keep Manager and Intern. What does the program gain? What does it lose?

Test

Check yourself

1. Shape is an abstract class. Which one compiles?
2. What does an abstract method not have?
3. Triangle extends the abstract Shape but does not write Area(). What happens?
4. Can an abstract class have fields, a constructor and ordinary methods?

Made by Ivo Gergov as part of Evo Tech's campaign for accessible programming education ·