CodeGym /Courses /C# SELF /Abstract Classes and Methods

Abstract Classes and Methods

C# SELF
Level 22 , Lesson 1
Available

1. Introduction

Abstract class — that's a class you can't just create directly with new. It's meant to be a base for other, more specific classes. Think of it as a template or "blueprint" that defines the general structure and behavior for derived classes, but leaves the details of the actual implementation to them.

Here's an analogy to make it easier: imagine you have the concept of "Transport". In real life, nobody rides around on an abstract "Transport" (unless it's in their imagination). Someone drives a car, someone sails a ship, someone flies a plane. The abstract class is your "Transport" blueprint, which says that any transport should have the key ability to move (Move), but how it does that should be defined in the child classes.


// Example of an abstract class
public abstract class Transport
{
    public string Model { get; set; }

    // Abstract method — no implementation
    public abstract void Move();
}

If you try to create an object of type Transport, you'll get a compile error! Try it — and the compiler will quickly scold you, like "can't create an instance of an abstract class".

When and why do you need abstract classes?

  • You want to group common characteristics and behavior of different but similar objects in one place.
  • You need to set a "single contract": for example, "all descendants must be able to move".
  • There's a common implementation for some methods, but part of the logic needs to be specified in derived classes.

An abstract class is an awesome tool for designing the architecture of a big system, where there are some common "features" for everyone, but the specifics should be implemented by each concrete descendant.

2. Difference between an abstract class and a regular class

This is where people often have questions, so let's break it all down!

Abstract class vs Regular class

  • Regular class can be created with new, and can have all implemented methods.
  • Abstract class:
    • can't be created directly (abstract in the class declaration)
    • can have both implemented and abstract (no body) methods
    • can have fields, properties, constructors, and even static methods

public abstract class Animal
{
    public string Name { get; set; }
    public void Sleep()
    {
        Console.WriteLine("The animal is sleeping!");
    }

    public abstract void MakeSound();
}

3. Abstract methods and properties

Abstract method

An abstract method is declared in an abstract class, but doesn't have a body (implementation). The derived class must implement it however it wants.


public abstract class Animal
{
    public string Name { get; set; }

    // Abstract method
    public abstract void MakeSound();
}

Abstract property

You can also declare an abstract property, so all descendants are required to implement it:


public abstract class Shape
{
    // Abstract property
    public abstract double Area { get; }
}

4. Inheriting from abstract classes

An abstract class can have both abstract and implemented methods. The derived class must implement all abstract methods and properties, or else it becomes abstract itself.

Let's expand our "animal app" we started in previous lectures:


public abstract class Animal
{
    public string Name { get; set; }

    public void Sleep()
    {
        Console.WriteLine($"{Name} is sleeping sweetly!");
    }

    public abstract void MakeSound();
}

Now let's create a regular, non-abstract class:


public class Dog : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine($"{Name} says: Woof!");
    }
}

Try not implementing MakeSound() — and you'll see a compile error.

Diagram: class hierarchy with an abstract class


+---------------------+
|   Animal (abstract) |
+---------------------+
| Name: string        |
| + Sleep()           |
| + MakeSound()*      |
+---------------------+
         ^
         |
  +------+-------+
  |              |
 Dog            Cat

* MakeSound() — abstract method

5. Polymorphism in action: how abstraction works in practice

Let's use all this in our mini-app. Imagine we have a list of animals — let's say dogs and cats.


List<Animal> animals = new List<Animal>
{
    new Dog { Name = "Sharik" },
    new Cat { Name = "Barsik" }
};

foreach (var animal in animals)
{
    animal.MakeSound(); // Polymorphic call: their own version runs
    animal.Sleep();     // Calls the method implemented in the base class
}

The Cat class is implemented similarly:


public class Cat : Animal
{
    public override void MakeSound()
    {
        Console.WriteLine($"{Name} says: Meow!");
    }
}

Practical value in real projects

Abstract classes are widely used in the architecture of big apps. For example, in graphic editors there's usually an abstract Shape class with methods like Draw() and properties like Area. Concrete shapes (rectangle, circle) implement these abstract methods with their own formulas. Thanks to this approach, you can create lots of different shapes without rewriting all the program logic.

6. Features and limitations of abstract classes

You can't create an instance

The compiler will absolutely forbid you from doing this:


Animal a = new Animal(); // Error!

Only derived (concrete) classes can be instantiated.

Abstract classes can contain:

  • Abstract method declarations (no implementation)
  • Implemented methods (with a body)
  • Properties and fields (abstract or implemented)
  • Constructors — yep, abstract classes can have constructors, but only descendants can call them, not code that creates an object directly.

Abstract classes support inheritance

You can build whole hierarchies of abstractions:


public abstract class Creature
{
    public abstract void Live();
}

public abstract class Animal : Creature
{
    public abstract override void Live();
    public abstract void MakeSound();
}

If a class in the inheritance chain doesn't implement all abstract methods, it must be declared abstract itself!

7. Abstract classes and constructors

An abstract class can have constructors, which will be called from the constructors of derived classes.
Important detail: constructors of abstract classes are usually declared protected to make it clear they're only for use by descendants, not for direct instance creation.


public abstract class Animal
{
    public string Name { get; set; }
    
    // Constructor declared as protected
    protected Animal(string name)
    {
        Name = name;
        Console.WriteLine($"Animal created with name {name}");
    }
    
    public abstract void MakeSound();
}

public class Dog : Animal
{
    public Dog(string name) : base(name)
    {
        // base(name) calls Animal's constructor
        Console.WriteLine("Dog created");
    }

    public override void MakeSound()
    {
        Console.WriteLine($"{Name} says: Woof!");
    }
}

Why use protected constructors?

  • Clear intent: protected clearly shows the constructor is only for descendants
  • Prevents mistakes: even though the compiler won't let you create an instance with new, a protected constructor makes this intent explicit at the class API level, removing even the theoretical chance for confusion
  • Good practice: follows encapsulation principles and a clear API

You can also use public constructors in abstract classes, but protected more accurately reflects their purpose.

8. Comparing abstract and virtual methods

Abstract methods are a kind of virtual method (they're basically always virtual, even though you don't use that word), but you can't write an implementation in them. If you want some methods to be optionally overridden by descendants (but not required), use virtual. If they must — only abstract.


public abstract class Worker
{
    // Everyone must implement
    public abstract void Work();

    // Anyone can override, but doesn't have to
    public virtual void Rest()
    {
        Console.WriteLine("Standard rest!");
    }
}
Abstract method Virtual method
Implementation in base class No, just the signature (declaration without a body) Yes, there's a default implementation
Where can you declare Only in an abstract class In any non-sealed class, including abstract ones
Descendant must override Required for the first non-abstract descendant Not required. You can override, or use the base implementation
Can be called directly No (method has no body) Yes (the base version will run)
Main purpose Force descendants to provide their own unique implementation. Define a "contract" Let descendants change behavior if needed

9. Using abstract classes in your project

Let's keep building our learning app. Now let's say we need an abstract class for handling user input (like different types of forms).


public abstract class InputForm
{
    public string Title { get; set; }

    // Abstract method that implements the input process
    public abstract void ShowAndHandleInput();
}

public class LoginForm : InputForm
{
    public override void ShowAndHandleInput()
    {
        Console.WriteLine($"=== {Title} ===");
        Console.Write("Enter login: ");
        string login = Console.ReadLine();
        Console.Write("Enter password: ");
        string password = Console.ReadLine();
        Console.WriteLine("Authentication complete!");
    }
}

public class RegistrationForm : InputForm
{
    public override void ShowAndHandleInput()
    {
        Console.WriteLine($"=== {Title} ===");
        Console.Write("Create a login: ");
        string login = Console.ReadLine();
        Console.Write("Create a password: ");
        string password = Console.ReadLine();
        Console.WriteLine("Registration complete!");
    }
}

Usage:


InputForm[] forms = new InputForm[]
{
    new LoginForm { Title = "Login" },
    new RegistrationForm { Title = "Registration" }
};

foreach (var form in forms)
{
    form.ShowAndHandleInput();
}

This approach gets more and more powerful as your program grows. An abstract class is a great foundation for building extensible systems, where DRY and SOLID principles (don't repeat yourself, write modular and easy-to-extend code) are your best friends.

10. Common mistakes when working with abstract classes and methods

Mistake #1: forgot to implement an abstract method.
If a derived class doesn't implement all abstract methods and properties, the compiler will throw an error. This happens a lot, especially when working with someone else's code or big hierarchies. Double-check that you didn't miss anything important.

Mistake #2: trying to make a method both abstract and static.
Nope, can't do that. Abstract methods are meant to be implemented in class instances, and static ones don't need an instance at all. These two approaches contradict each other, and the compiler won't let you compile it.

Mistake #3: "lazy" avoidance of implementing all abstract members.
If you don't want to implement all abstract methods, you'll have to make the class abstract too. That's not a mistake per se, but it might be a sign of a confusing architecture. Sometimes it makes sense to move partial implementation to an intermediate abstract class to make life easier for descendants.

2
Task
C# SELF, level 22, lesson 1
Locked
Creating an abstract class and a derived class
Creating an abstract class and a derived class
2
Task
C# SELF, level 22, lesson 1
Locked
Abstract class and polymorphism
Abstract class and polymorphism
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION