CSS Prepare

optional · CSS study notes

15. Abstract Class

A class containing at least one pure virtual function — cannot be instantiated directly, only used as a base for derived classes.

class Shape           // abstract -- has a pure virtual function
{
public:
    virtual double area() = 0;
};

// Shape s;   // ERROR

Shape* s = new Circle(5);   // OK -- can still use it via a pointer to a CONCRETE derived class

An abstract class may still contain regular (non-pure) member functions with real implementations — it just needs at least one pure virtual function to qualify as abstract.

The defining rule and what it means practically

A class becomes abstract the moment it has even one pure virtual function — regardless of how many other fully-implemented methods it has.

class Shape
{
public:
    virtual double area() = 0;              // pure virtual -- makes Shape abstract
    void printInfo() { cout << "A shape\n"; }   // regular, fully implemented -- doesn't change the abstractness
};

// Shape s;             // ERROR -- abstract, cannot instantiate
Shape* s = new Circle(5);   // OK -- pointer to abstract class is fine, as long as Circle is concrete

Purpose: defining a contract, not an implementation

An abstract class exists to say "every shape MUST have an area, but I won't say how" — it defines what derived classes must provide, without dictating how. This is the core idea behind interface-style design in C++.

Abstract classes CAN have constructors

class Shape
{
protected:
    string color;
public:
    Shape(string c) : color(c) {}   // abstract classes CAN have constructors -- called by derived class constructors
    virtual double area() = 0;
};

class Circle : public Shape
{
    double radius;
public:
    Circle(string c, double r) : Shape(c), radius(r) {}   // must call Shape's constructor
    double area() override { return 3.1416 * radius * radius; }
};

A common misconception: "abstract means no constructor." False — the constructor still runs (to initialize shared state like color), it just can never be called to create a Shape object directly, only as part of constructing a derived object.

Important MCQs

  1. A class becomes abstract as soon as it has:
    • a) Any private member b) At least one pure virtual function c) A constructor d) Any static member
  2. Can an abstract class have a constructor?
    • a) No, never b) Yes — it runs when a derived (concrete) object is constructed c) Only if it has no data members d) Only in Java
  3. Can you create a pointer of an abstract class type pointing to a concrete derived object?
    • a) No, never allowed b) Yes — Shape* s = new Circle(); is valid c) Only with static_cast d) Only in structs

Self-Test Questions

  1. Can an abstract class have fully-implemented (non-pure) member functions? Give an example use case.
  2. Why can an abstract class still have a constructor if it can never be instantiated directly?
  3. What is the practical purpose of declaring a class abstract, rather than just leaving area() unimplemented with an empty body?

📌 Sample & Repeated FPSC Questions (2016–2026)

2020, Paper I, Q2(c) (5 marks) — Explain the concept of abstract class with an example.

An abstract class cannot be instantiated on its own and exists only to be inherited from. It typically contains at least one pure virtual function (virtual returnType func() = 0;) with no implementation — derived classes are forced to override it before they can be instantiated. It defines a common interface/contract (and optionally shared partial implementation) for a family of related classes, enabling polymorphism.

class Shape {
public:
    virtual double area() = 0;   // pure virtual -> Shape is abstract
    virtual void draw() { cout << "Drawing a shape" << endl; }
};
class Circle : public Shape {
    double radius;
public:
    Circle(double r): radius(r) {}
    double area() override { return 3.14159 * radius * radius; }
};

Shape s; fails to compile; Circle c(5); succeeds since it implements area(). A Shape* can then point to any concrete subclass and dispatch to the right area() at runtime.


2023, Paper I, Q4(c) (6 marks) — Differentiate between Abstraction & Encapsulation.

  • Abstraction (design-level): hiding unnecessary implementation complexity, exposing only essential features/behaviour — "what an object does." Achieved via abstract classes, interfaces, or well-designed public method signatures.
  • Encapsulation (implementation-level): bundling data and the methods that operate on it into one unit (a class), restricting direct external access to internal state — "how it is hidden." Achieved via access specifiers (private/protected) plus controlled public getters/setters.

In short: abstraction hides complexity from the user's perspective (interface design); encapsulation hides/protects data from unauthorized access (implementation protection). They work together — encapsulation is often the mechanism used to enforce abstraction, and an abstract class is one concrete C++ tool for achieving abstraction.

MCQ Trap: abstraction and encapsulation are frequently confused on MCQs — abstraction ≈ interface/"what," encapsulation ≈ data-hiding/"how."


2026, Paper I, Q4(a) (6 marks) — Why cannot we instantiate an abstract class directly, even though it may contain complete functions?

A class is abstract the moment it declares even one pure virtual function (= 0), no matter how many other fully-implemented ("complete") member functions it also has — one incomplete function is enough to leave the whole class's interface incomplete. If instantiation were allowed and code then called that unimplemented function, there would be no body to execute — undefined, unsafe behaviour. So C++ makes this a compile-time error. The class can only be "brought to life" indirectly: a derived class supplies a concrete implementation for every pure virtual function, and only that derived class becomes instantiable — while the abstract base can still hand down shared, complete helper functions (like printInfo() in this page's own example) to all its derived classes.

📜 Past-Paper Questions & MCQs (CSS 2016–2026)

2020 · Paper-I · Q2(c) · 5 marks

Q. Explain the concept of an abstract class with an example.

Ans.

  • An abstract class is a class that cannot be instantiated. It exists to be a base class that defines a common interface and shared code. It contains at least one pure virtual function.
  • Purpose: to force derived classes to implement certain functions and to support polymorphism.
class Employee {                         // abstract
public:
    virtual double salary() = 0;         // pure virtual
};
class Manager : public Employee { public: double salary() override { return 150000; } };
// Employee e;         // error
Employee *e = new Manager();   // allowed: base-class pointer to derived object

2026 · Paper-I · Q4(a) · 6 marks

Q. Why can we not instantiate an abstract class directly, even though it may contain complete functions?

Ans.

  • An abstract class is incomplete by definition. At least one function (the pure virtual function) has no implementation, so an object of that class would have a function that cannot be called.
  • The compiler therefore blocks instantiation, even if all other functions are fully written.
  • The class is a design contract. It is meant to be extended, and only a derived class that implements all pure virtual functions becomes concrete and can be instantiated.
  • What you can do: create objects of the derived class, and use pointers or references of the abstract type to refer to them.

2021 · Paper-I · Q4(b) · 6 marks

Q. Why do we need interfaces in OOP? How do they help achieve abstraction?

Ans.

  • An interface declares a set of methods that implementing classes must provide, without giving any implementation. In C++ it is an abstract class with only pure virtual functions. In Java it is declared with interface.
  • Why needed:
    • to define a contract that many unrelated classes can follow
    • to allow multiple inheritance of type (a Java class can implement many interfaces)
    • to give loose coupling, since code depends on the interface and not on a particular class
  • Abstraction: users of the interface know what can be done but not how it is done. For example, a Payment interface with pay() can be implemented by CreditCard and Wallet.