README
1 min read15 headings
Abstract Classes in C++
Table of Contents
- What are Abstract Classes
- Pure Virtual Functions
- Interface Pattern
- Abstract vs Concrete
- Partial Implementation
- Best Practices
What are Abstract Classes
An abstract class cannot be instantiated - it serves as a base for other classes.
class Shape {
public:
virtual double area() = 0; // Pure virtual = abstract
};
// Shape s; // ERROR: cannot instantiate
Purpose
- Define interfaces
- Enforce derived class contracts
- Provide common base functionality
Pure Virtual Functions
A function with = 0 is pure virtual:
class Animal {
public:
virtual void speak() = 0; // Must be overridden
virtual void move() = 0; // Must be overridden
void breathe() { // Regular method - inherited
cout << "Breathing" << endl;
}
virtual ~Animal() = default;
};
class Dog : public Animal {
public:
void speak() override { cout << "Woof!" << endl; }
void move() override { cout << "Running" << endl; }
};
Rules
- Class with any pure virtual = abstract
- Derived class must override ALL pure virtuals to be concrete
- Pure virtuals CAN have implementation (see below)
Interface Pattern
Pure interfaces have ONLY pure virtual functions:
class IDrawable {
public:
virtual void draw() = 0;
virtual ~IDrawable() = default;
};
class IClickable {
public:
virtual void onClick() = 0;
virtual ~IClickable() = default;
};
class Button : public IDrawable, public IClickable {
public:
void draw() override { cout << "[Button]" << endl; }
void onClick() override { cout << "Clicked!" << endl; }
};
Naming Convention
- Prefix with
I(IDrawable, ISerializable) - Or suffix with
able(Drawable, Serializable)
Abstract vs Concrete
| Abstract Class | Concrete Class |
|---|---|
| Has ≥1 pure virtual | No pure virtuals |
| Cannot instantiate | Can instantiate |
| Serves as interface/base | Fully implemented |
// Abstract - has pure virtual
class Vehicle {
public:
virtual void drive() = 0;
};
// Still abstract - didn't implement all
class Car : public Vehicle {
// drive() still pure virtual
};
// Concrete - all implemented
class Sedan : public Car {
public:
void drive() override { cout << "Driving sedan" << endl; }
};
Sedan s; // OK
// Car c; // ERROR
// Vehicle v; // ERROR
Partial Implementation
Abstract classes can provide default implementations:
class Logger {
public:
virtual void log(const string& msg) = 0;
// Default implementations
void info(const string& msg) { log("[INFO] " + msg); }
void error(const string& msg) { log("[ERROR] " + msg); }
virtual ~Logger() = default;
};
class ConsoleLogger : public Logger {
public:
void log(const string& msg) override {
cout << msg << endl;
}
};
ConsoleLogger logger;
logger.info("Started"); // Uses inherited info()
logger.error("Failed"); // Uses inherited error()
Pure Virtual WITH Body
class Base {
public:
virtual void method() = 0; // Still abstract!
};
// Provide default implementation
void Base::method() {
cout << "Default implementation" << endl;
}
class Derived : public Base {
public:
void method() override {
Base::method(); // Can call default
cout << "Extended" << endl;
}
};
Best Practices
✅ Do
// 1. Virtual destructor
class Interface {
public:
virtual void method() = 0;
virtual ~Interface() = default;
};
// 2. Use for polymorphism
void process(Shape& s) { s.draw(); }
// 3. Keep interfaces small
class IReader { virtual void read() = 0; };
class IWriter { virtual void write() = 0; };
❌ Don't
// 1. Don't add data members to pure interfaces
class IBad {
int data; // Avoid in pure interfaces
virtual void method() = 0;
};
// 2. Don't forget to implement all pure virtuals
class Incomplete : public Animal {
void speak() override {}
// Forgot move() - still abstract!
};
Quick Reference
// Abstract class
class Abstract {
public:
virtual void pureMethod() = 0; // Must override
virtual void withDefault() {} // Can override
void concrete() {} // Regular method
virtual ~Abstract() = default;
};
// Pure interface
class IInterface {
public:
virtual void method1() = 0;
virtual void method2() = 0;
virtual ~IInterface() = default;
};
// Concrete implementation
class Concrete : public Abstract, public IInterface {
public:
void pureMethod() override {}
void method1() override {}
void method2() override {}
};
Compile & Run
g++ -std=c++17 -Wall examples.cpp -o examples && ./examples