The topmost abstract class in a hierarchy, specifically designed as a common interface for all its derived classes — typically has most or all of its functions as pure virtual, providing little to no implementation of its own.

Distinction from a plain Abstract Class: every abstract super class is an abstract class, but not every abstract class is the super class of its hierarchy — a class one level down that still has one unimplemented pure virtual function is abstract too, just not the super class.

class Shape                          // Abstract SUPER class -- pure interface, top of hierarchy
{
public:
    virtual double area() = 0;
    virtual double perimeter() = 0;
};

class Polygon : public Shape         // Also abstract (area() still unimplemented) but NOT the super class
{
public:
    double perimeter() override { return 0; }
};

class Square : public Polygon        // Concrete -- implements everything, CAN be instantiated
{
    double side;
public:
    Square(double s) : side(s) {}
    double area() override { return side * side; }
};

A 3-level hierarchy, fully worked

class Shape                          // ABSTRACT SUPER CLASS -- top of hierarchy, pure interface
{
public:
    virtual double area() = 0;
    virtual double perimeter() = 0;
    virtual ~Shape() {}
};

class Polygon : public Shape         // ALSO abstract (still hasn't implemented area()) -- but NOT the super class
{
public:
    double perimeter() override { return 0; }   // provides ONE implementation, still abstract overall
    // area() remains pure virtual here -- Polygon is still not instantiable
};

class Square : public Polygon        // CONCRETE -- every pure virtual is now implemented
{
    double side;
public:
    Square(double s) : side(s) {}
    double area() override { return side * side; }
};

int main()
{
    // Shape s;      // ERROR
    // Polygon p;    // ERROR -- still abstract
    Square sq(4);     // OK -- fully concrete
    Shape* s = new Square(4);   // OK -- pointer to the abstract super class, holding a concrete object
    cout << s->area();          // 16 -- resolved via virtual dispatch
    return 0;
}

The distinction, precisely

Polygon sits in an unusual middle position — it's abstract, but it's not the super class, since it already provides one implementation and sits below Shape.

Why this design is useful

Client code can write Shape* shapes[] and store any concrete shape (Square, Circle, Triangle, etc.) — the abstract super class defines the common contract (area(), perimeter()) that every concrete shape must fulfill, enabling polymorphic collections.

Important MCQs

  1. The "abstract super class" refers specifically to:
  2. A middle class (like Polygon) that is abstract but not the topmost class is:
  3. The purpose of an abstract super class is mainly to:

Self-Test Questions

  1. Why is Polygon considered abstract, but not the "abstract super class" of this hierarchy?
  2. What would happen if you tried to instantiate Polygon directly?
  3. What's the practical benefit of having Shape define area() and perimeter() as pure virtual, rather than each concrete class defining unrelated method names?