C#. An example of using an abstract class that contains abstract properties and methods

An example of using an abstract class that contains abstract properties and methods

The example describes in detail the step-by-step process of developing an abstract class that contains abstract properties and methods.

After completing these instructions, you will learn:

  • develop programs using abstract classes, abstract methods and properties;
  • create class hierarchies that maximize the benefits of polymorphism.

Contents


Task

Develop an abstract class Figure, which define the following elements:

  • private internal field name (figure name);
  • a constructor with 1 parameter, initializing the name field with the specified value;
  • Name property to access the internal name field;
  • the Area2 abstract property, intended to obtain the area of the figure;
  • the Area() abstract method, intended to obtain the area of a figure;
  • virtual method Print(), which displays the name of the figure.

Develop a Triangle class that inherits (extends) the capabilities of the Figure class. The class realize the following elements:

  • hidden internal fields a, b, c (sides of the triangle);
  • constructor with 4 parameters;
  • methods SetABC(), GetABC() for accessing the fields of the class. Each method receives 3 parameters which are the lengths of the sides of the triangle;
  • the Area2 property that defines the area of a triangle along its sides a, b, c;
  • Area() method that returns the area of a triangle by its sides;
  • virtual method Print() to display the internal fields of the class. The method refers to the same method of the base class.

 

Theoretical information

An abstract class is a class in which there is at least one abstract element (method, property). If an abstract element (method, property) is declared in an abstract class, then the keyword abstract is placed in front of the name of such a class. An abstract method does not contain a method body. If in a derived class it is necessary to determine the concrete implementation of an element (method, property) of an abstract class, then the override keyword is indicated when declaring an element.

 

Instructions

1. Create an application using the Console Application template. The text of the program

In different versions of Microsoft Visual Studio, the window interface for creating applications is different. But, in general, to create an application, you need to call the New… command from the File menu. As a result, a window opens in which you need to set the C# programming language and select Console Application from the list of available project templates.

As a result, a refinement window opens in which you need to set the name of the application (ConsoleApplication1), a folder for the project and, possibly, other settings.

 

2. The initial text of the program

After creating the application, the system will create basic program code that can be modified.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
  class Program
  {
    static void Main(string[] args)
    {
    }
  }
}

As you can see from the above code, a C# program contains a declaration of the Program class. In the Program class, the static function Main() is declared, which serves as the entry point to the program. In this function, the program code for testing the work of the developed classes will be added later.

 

3. Considerations regarding the general arrangement and construction of classes

In accordance with the condition of the task, the program needs to develop 2 classes: Figure, Triangle. To keep things simple, classes will be placed in the ConsoleApplication1 namespace before declaring the Program class.

// General class placement
namespace ConsoleApplication1
{
  abstract class Figure
  {
    ...
  }

  class Triangle : Figure
  {
    ...
  }

  class Program
  {
    static void Main(string[] args)
    {
    }
  }
}

As you can see from the code above, the abstract keyword is specified before the declaration of the Figure class. This means that this class is abstract, since abstract methods and properties will be placed in it (see the code below).

 

4. Develop an abstract class Figure
4.1. Internal field name. Set figure name

First, you need to add a hidden (private) internal variable name to the body of the abstract class. This variable is the name of the figure. The figure name is of type string. After that, the text of the class Figure has the following form

...

abstract class Figure
{
  // 1. Hidden field of class
  private string name; // The name of figure
}

...

 

4.2. Adding a class constructor. Initialize class internal field

The constructor of the Figure class must initialize the internal field name with the value when an instance (object) of this class is created. The constructor has public visibility. At the moment, the text of the class Figure is as follows.

...

abstract class Figure
{
  // 1. Hidden field of class
  private string name; // The name of figure

  // 2. Class constructor
  public Figure(string name)
  {
    this.name = name;
  }
}

...

 

4.3. Property Name. Access to the Figures class internal field

To access the internal field from an instance, create the Name property. Since you can write (and read) to the internal field, the Name property will be of type get/set.

abstract class Figure
{
  ...

  // 3. The property to class field access
  public string Name
  {
    get { return name; }
    set { name = value; }
  }
}

 

4.4. Abstract property Area2. Get the area of the figure

In accordance with the condition of the problem, the class should have an abstract property Area2, which returns the area of the figure. The property is abstract, because the Figure class is a general outline. At this stage, it is not known what shape this is: a circle, a rectangle, a triangle, or another. Therefore, it is impossible to determine the area of the figure at the moment. So, the Area2 property should be abstract. The presense an abstract property makes the entire Figure class also abstract.

...

abstract class Figure
{
  ...

  // 4. An abstract property that returns the area of a figure
  public abstract double Area2 { get; }
}

...

In the above code, to indicate that the Area2 property is abstract, the abstract keyword is specified before its declaration.

In addition, this property has the following characteristics:

  • the property is automatic. The get specifier symbolizes this without specifying curly braces { }. An automatic property means that the compiler itself creates an additional field to represent the value. In this case, this is superfluous;
  • the property is read-only (get), therefore it does not contain the set specifier.

 

4.5. Abstract Area() method. Get the area of the figure

In the generalized Figure class, the method for calculating the area area of Area() is declared abstract for the same reasons as the Area2 property (see section 4.4.)

The code for the Area() method in the Figure class is as follows

...

abstract class Figure
{
  ...

  // 5. Abstract method that returns the area of a figure
  //   The method does not have a method body
  public abstract double Area();
}

...

 

4.6. Virtual method Print(). Displaying the class field values

This example demonstrates the use of polymorphism. In the Figure class, a virtual Print() method is declared, which can be used in inherited classes to display the values of the class’s internal fields.

The text of the Print() method in the Figure class is as follows

...

abstract class Figure
{
  ...
  // 6. A virtual method that displays the value of the fields of a class
  public virtual void Print()
  {
    Console.WriteLine("name = {0}", name);
  }
}

...

In order for the base class method to take full advantage of polymorphism (virtual method), it must be declared with the virtual keyword. This means that all methods of derived classes that have the same name Print() and parameters can be called in a single way by reference to the base class Figure. Below, in the main() function, this will be demonstrated. For the Print() methods of derived classes to polymorphism, you must specify an override specifier in their declaration.

 



5. The developing of Triangle class

The Triangle class represents a specific geometric figure – triangle defined by its sides a, b, c. Unlike the Figure class, the Triangle class is not abstract – this is a specialization of the generalized Figure class.

5.1. Internal class fields. Sides of the triangle

The Triangle class is represented by the lengths of the sides a, b, c of the triangle. The class is derived from the abstract class Figure.

The internal fields of the Triangle class with the corresponding names are of type double. The internal fields of the Triangle class with the corresponding names are of type double.

...

// Class that implements a triangle. There are no abstract methods in the class,
// so the word abstract is not placed before the class declaration.
class Triangle : Figure
{
  // 1. Internal class fields
  double a, b, c;
}

...

 

5.2. Constructor Triangle(). Initialization of internal fields of the base class Figures and derived class Triangle

Triangle-class constructor is called during the creation of an instance of this class. This constructor invokes the constructor of the base class Figure using the base keyword. In this case, this is necessary in accordance with the requirements of the compiler: the constructor of the base class is executed first, and then the constructor of the derived class is executed.

The constructor of the Triangle() class has 4 parameters:

  • a parameter name – the name of figure. This is the field of base class Figure;
  • three parameters a, b, c which are the lengths of the sides of the triangle. In the body of the constructor, a check is made for the correctness of the indication of the sides a, b, c.

The constructor text in the class is as follows

...

class Triangle : Figure
{
  ...

  // 2. Class constructor
  public Triangle(string name, double a, double b, double c)
                : base(name)
  {
    // Checking the correctness of the values of a, b, c
    if (((a + b) > c) && ((b + c) > a) && ((a + c) > b))
    {
      this.a = a; this.b = b; this.c = c;
    }
    else
    {
      Console.WriteLine("Incorrect values a, b, c.");
      Console.WriteLine("By default: a=1, b=1, c=1.");
      this.a = this.b = this.c = 1;
    }
  }

...

 

5.3. Method SetABC().Writing values to internal fields of the Triangle class

The SetABC() method is designed to write values to the fields of an instance of the class. The method is public and does not contain additional qualifiers.

The text of the SetABC() method in the class body is as follows

...

class Triangle : Figure
{
  ...

  // 3. Implementation of access methods to hidden fields a, b, c
  // 3.1. Setting field values a, b, c
  public void SetABC(double a, double b, double c)
  {
    if (((a + b) > c) && ((b + c) > a) && ((a + c) > b))
    {
      this.a = a; this.b = b; this.c = c;
    }
    else
    {
      this.a = this.b = this.c = 1;
    }
  }
}

...

 

5.4. Method GetABC(). Get the value of the internal fields of the Triangle class

To get the value of the class fields, the GetABC() method is used. Field values are obtained using the method parameters, which are implemented as out-parameters. It should be recalled that the out-parameter of the method allows changing the values of the argument in the calling code. The out parameter must be assigned values inside the method body, otherwise the compiler will generate an error message.

The text of the GetABC() method in the Triangle class is as follows

...

class Triangle : Figure
{
  ...

  // 3.2. Reading the field values - pay attention to the out modifier
  public void GetABC(out double a, out double b, out double c)
  {
    // set the parameter a to the value of the internal field a (this.a)
    a = this.a;

    // write values to other parameters in the same way
    b = this.b;
    c = this.c;
  }
}

...

 

5.5. Property Area2. Overriding the abstract property of the base class Figures

In accordance with the condition of the problem, in the Triangle class you need to implement the Area2 property, which will calculate the area of the triangle. This property overrides the eponymous property of the base class Figure. Therefore, the override keyword is specified in the property declaration.

The Area2 property itself in the Triangle class can no longer be abstract. This is due to the fact that, based on the values of the fields a, b, c, it is possible to calculate the area of the triangle (according to the Heron formula) without any problems. In the same property of the base class of the Figure class, this cannot be done, because it is not known for which figure to calculate the area (triangle, circle, rectangle), since the Figure class is the base for all the figures that will be inherited from it.

The Area2 property is intended to obtain the area of a triangle by the values of the internal fields a, b, c of the Triangle class. Therefore, the property is implemented with the get accessor and is read-only. In this property, it makes no sense to use the set accessor.

The program code for the Area2 property in the Triangle class is as follows

...

class Triangle : Figure
{
  ...

  // 4. Overriding the Area2 abstract property of the Figure class,
  // the override keyword is required
  public override double Area2
  {
    get
    {
      // 1. Make calculations
      double p, s;
      p = (a + b + c) / 2;
      s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));

      // 2. Display the result in property
      Console.WriteLine("Property Triangle.Area2: s = {0:f3}", s);

      // 3. Return the result
      return s;
    }
  }
}

 

5.6. Method Area(). Overriding the abstract method of the base class Figures

The Area() method of the Triangle class redefines (override) the eponymous abstract method of the base class Figure. Therefore, when declaring the Area() method, an override specifier is specified. A pair of these methods provides the so-called polymorphism. More details about the advantages and features of the use of polymorphism are described here.

When declaring a method (or property) in an abstract class, it makes no sense to indicate two words abstract and virtual at the same time in order to provide polymorphism. If the class is abstract, then only one word abstract is enough. If the class is not abstract, then virtual is specified.

The text of Area() method in the class Triangle

 

...

class Triangle : Figure
{
  ...

  // 5. An implementation of the Area() method,
  // which is declared as abstract in the Figure class
  public override double Area()
  {
    // 1. Make calculations
    double p, s;
    p = (a + b + c) / 2;
    s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));

    // 2. Display the result in the property - for control
    Console.WriteLine("Method Triangle.Area(): s = {0:f3}", s);

    // 3. Return the result
    return s;
  }
}

...

 

5.7. Method Print().Overriding a virtual function of a base class

In accordance with the condition of the problem, the Print() function should be used in the Triangle class, which is designed to display the values of the internal fields of the class. This function overrides the virtual function of the same name in the base class Figures, therefore, when declaring a function, the keyword override is specified.

In the body of the Print() method, the base class method of the same name is called using the string

// Invoke the Print() method of base class - optional
base.Print();

The text of the Print() method in the Triangle class is as follows:

...

class Triangle : Figure
{
  ...

  // 6. The Print () method, which overrides
  // the Figures base class method of the same name
  public override void Print()
  {
    // Calling the Print () method of the base class is optional
    base.Print();

    // Print the values of internal fields a, b, c
    Console.WriteLine("a = {0:f2}", a);
    Console.WriteLine("b = {0:f2}", b);
    Console.WriteLine("c = {0:f2}", c);
  }
}

 

6. Implementation of function Main().Testing the class

The Main() function of the Program class tests the operation of the Figures and Triangle classes.

...

class Program
{
  static void Main(string[] args)
  {
    // Demonstration of polymorphism using an abstract class.
    // 1. Reference to the base class
    Figure refFg;

    // 2. Declare an instance of class Figure
    // 2.1. Unable to instantiate abstract class
    // Figure objFg = new Figure("Figure"); - error!

    // 2.2. Declare the instance of class Triangle
    Triangle Tr = new Triangle("Triangle", 2, 3, 2);

    // 3. Call the Print() method using a reference to the base class
    refFg = Tr;
    refFg.Print();

    // 4. Call the Area() method using a reference to the bse class
    refFg = Tr;
    refFg.Area(); // Invoke the Triangle.Area() method

    // 5. Using the Area2 property using a reference to the base class
    refFg = Tr;
    double area = refFg.Area2; // property Triangle.Area2
    Console.WriteLine("area = {0:f3}", area);

    Console.ReadKey();
  }
}

...

 

7. The text of the program. Results

Below is the text of the entire program that solves this problem.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication8
{
  // Abstract Figure class - contains the abstract Area()
  // method and the abstract Area2 property
  abstract class Figure
  {
    // 1. Hidden field of class
    private string name; // The name of figure

    // 2. Class constructor
    public Figure(string name)
    {
      this.name = name;
    }

    // 3. The property to class field access
    public string Name
    {
      get { return name; }
      set { name = value; }
    }

    // 4. Abstract property that returns the area of a figure
    public abstract double Area2 { get; }

    // 5. Abstract method that returns the area of a shape
    //     The method does not have a method body
    public abstract double Area();

    // 6. A virtual method that displays the value of the fields of a class
    public virtual void Print()
    {
      Console.WriteLine("name = {0}", name);
    }
  }

  // A class that implements a triangle. There are no abstract
  // methods in the class, so the word abstract
  // is not placed before the class declaration.
  class Triangle : Figure
  {
    // 1. Internal fields of class
    double a, b, c;

    // 2. Class constructor
    public Triangle(string name, double a, double b, double c)
                : base(name)
    {
      // Validation of the values of a, b, c
      if (((a + b) > c) && ((b + c) > a) && ((a + c) > b))
      {
        this.a = a; this.b = b; this.c = c;
      }
      else
      {
        Console.WriteLine("Incorrect values a, b, c.");
        Console.WriteLine("By default: a=1, b=1, c=1.");
        this.a = this.b = this.c = 1;
      }
    }

    // 3. Implementation of access methods to hidden fields a, b, c
    // 3.1. Set the values of fields a, b, c
    public void SetABC(double a, double b, double c)
    {
      if (((a + b) > c) && ((b + c) > a) && ((a + c) > b))
      {
        this.a = a; this.b = b; this.c = c;
      }
      else
      {
        this.a = this.b = this.c = 1;
      }
    }

    // 3.2. Reading field values - pay attention to out modifier
    public void GetABC(out double a, out double b, out double c)
    {
      a = this.a; b = this.b; c = this.c;
    }

    // 4. Overriding the Area2 abstract property of the Figure class,
    //   the override keyword is required
    public override double Area2
    {
      get
      {
        // 1. Make calculations
        double p, s;
        p = (a + b + c) / 2;
        s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));

        // 2. Print the result
        Console.WriteLine("Property Triangle.Area2: s = {0:f3}", s);

        // 3. Return the result
        return s;
      }
    }

    // 5. An implementation of the Area () method,
    //   which is declared as abstract in the Figure class
    public override double Area()
    {
      // 1. Make calculations
      double p, s;
      p = (a + b + c) / 2;
      s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));

      // 2. Print the result
      Console.WriteLine("Method Triangle.Area(): s = {0:f3}", s);

      // 3. Return the result
      return s;
    }

    // 6. Virtual method Print
    public override void Print()
    {
      base.Print();
      Console.WriteLine("a = {0:f2}", a);
      Console.WriteLine("b = {0:f2}", b);
      Console.WriteLine("c = {0:f2}", c);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      // Demonstration of polymorphism using an abstract class.
      // 1. Declare a reference to the base class
      Figure refFg;

      // 2. Declare an instance of class Figure
      // 2.1. Unable to instantiate abstract class
      // Figure objFg = new Figure("Figure"); - error!

      // 2.2. Declare an instance of class Triangle
      Triangle Tr = new Triangle("Triangle", 2, 3, 2);

      // 3. Invoke the Print() method using the reference to base class
      refFg = Tr;
      refFg.Print();

      // 4. Calling the Area() method with a reference to the base class
      refFg = Tr;
      refFg.Area(); // method Triangle.Area() is called

      // 5. Using the Area2 property using a reference to base class
      refFg = Tr;
      double area = refFg.Area2; // property Triangle.Area2
      Console.WriteLine("area = {0:f3}", area);

      Console.ReadKey();
    }
  }
}

The result of the program

name = Triangle
a = 2,00
b = 3,00
c = 2,00
Method Triangle.Area(): s = 1,984
Property Triangle.Area2: s = 1,984
area = 1,984

 

8. The task for the knowledge test

We need to complete the previous program by adding another class to it.

Develop a TriangleColor class that inherits (extends) the capabilities of the Triangle class. In the class, implement the following elements:

  • hidden internal field color;
  • a constructor with 5 parameters, which will call the constructor of the base class;
  • property Color for accessing the internal color field;
  • the Area2 property, which calls the base class property of the same name to calculate the area of a triangle;
  • method Area() that returns the area of a triangle along its sides;
  • virtual method Print() to display the internal fields of the class. The method refers to the same method of the base class.

The full text of the program with the text of the TriangleColor class can be viewed here.

 


Related topics