Types · design
abstract class vs interface
Both let callers program against a contract instead of a concrete type. The difference is what else they carry: an abstract class is a half-built family member (state, constructors, shared code); an interface is a pure promise any unrelated class can make.
The comparison that matters
| abstract class | interface | |
|---|---|---|
| Can hold state (fields) | yes | no (pre-C# 8) |
| Can have a constructor | yes | no |
| Can ship shared method code | yes | not before C# 8 (default methods are new and rare) |
| How many can one class use? | one | many |
| Relationship it models | "is a kind of" (a Dog is an Animal) | "is able to" (a Robot can speak) |
| Instantiate directly? | no | no |
abstract class: shared state plus a required override
An abstract class is the right tool when subclasses share both data and obligations:
abstract class Shape
{
public string Name; // shared state
protected Shape(string name) { Name = name; }
public abstract double Area(); // every subclass MUST implement this
public void Describe() // shared code, written once
{
Console.WriteLine(Name + " area=" + Area().ToString("F2"));
}
}
class Circle : Shape
{
private double r;
public Circle(double r) : base("Circle r=" + r) { this.r = r; }
public override double Area() { return Math.PI * r * r; }
}
class Square : Shape
{
private double s;
public Square(double s) : base("Square s=" + s) { this.s = s; }
public override double Area() { return s * s; }
}
new Circle(2).Describe();
new Square(3).Describe();
Notice what the abstract class bought you: the Name field, the constructor and Describe() exist once, inherited by every shape. If this were an interface, each class would have to re-implement Describe() (and could not have the field at all in older C#).
interface: a promise across unrelated families
An interface is the right tool when the classes that need it share nothing except the ability:
interface IPrintable
{
void Print();
}
class Report : IPrintable
{
private string title;
public Report(string t) { title = t; }
public void Print() { Console.WriteLine(title + " printed"); }
}
class Invoice : IPrintable
{
public void Print() { Console.WriteLine("Invoice printed"); }
}
IPrintable[] queue = { new Report("Report A"), new Invoice(), new Report("Report B") };
foreach (IPrintable item in queue)
{
item.Print(); // one loop, three behaviours, zero shared ancestry
}
A Report and an Invoice have no business sharing a base class — they're not the same kind of thing. But both can be printed, so both can implement IPrintable, and one queue can hold them.
Why "one abstract class, many interfaces"
C# allows a class to inherit from a single base class but to implement unlimited interfaces. This is deliberate:
- Inheritance carries state and code, and multiple inheritance of state is a swamp (the diamond problem). One parent keeps the memory layout predictable.
- Interfaces carry only obligations, and there is no such problem with many obligations. Implementing five interfaces is just five lists of methods to write.
So the practical shape is: one abstract base for shared implementation, plus several interfaces for capabilities:
abstract class Employee { /* shared: Name, Salary, common methods */ }
interface IReportable { void FileReport(); }
interface IApprovable { void Approve(); }
class Manager : Employee, IReportable, IApprovable
{
public void FileReport() { … }
public void Approve() { … }
}
When abstract classes go wrong
They're the most-abused tool in OOP. Two symptoms to watch:
- Empty abstract classes with no state and no shared code — that's an interface wearing a class costume, and it consumes your one inheritance slot for nothing.
- Deep hierarchies (Base → SubBase → SubSubBase) — each level adds coupling without clarity. Two levels is usually enough; a composition (holding an object) beats a third level of inheritance.
Decision guide
| If… | Use |
|---|---|
| Subclasses share fields, a constructor or common method bodies | abstract class |
| The relationship is genuinely "X is a kind of Y" | abstract class (or plain inheritance) |
| Unrelated classes need to promise the same capability | interface |
| A class needs several of these at once | interface (the only option) |
| You're unsure | start with an interface — it's the cheaper commitment |
Frequently asked
Can an abstract class have a constructor?
Yes — and it's useful: subclasses call it with : base(…) to initialize shared fields. It just can't be called via new on the abstract type itself.
Does an interface need every method implemented?
Yes, every non-default member must be implemented by the implementing class, or the compiler errors. That's the enforcement behind the promise.
Can one class have both?
Yes: class Manager : Employee, IReportable, IApprovable — one base class, then any number of interfaces after it.