CSS Prepare

optional · CSS study notes

9. Forms of Inheritance

FormStructureExample
SingleOne base → one derivedAnimal → Dog
MultipleOne derived ← two or more basesFlyingRobot ← Flyable • Robot
MultilevelChain: base → derived → further derivedAnimal → Mammal → Dog
HierarchicalOne base → multiple independent derived classesShape → Circle, Square, Triangle
HybridCombination of two or more forms aboveDiamond-shaped hierarchies — can trigger the "diamond problem"
// Diamond problem (hybrid inheritance)
class A { public: int x; };
class B : public A {};
class C : public A {};
class D : public B, public C {};   // D has TWO copies of A::x -- ambiguous!

// Fixed with virtual inheritance:
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};   // now only ONE shared copy of A::x

Each form, with a runnable example

Single inheritance

class Animal { public: void eat() { cout << "eats\n"; } };
class Dog : public Animal { public: void bark() { cout << "barks\n"; } };
// Dog gets eat() + adds bark()

Multiple inheritance

class Flyable { public: void fly() { cout << "flies\n"; } };
class Robot { public: void compute() { cout << "computes\n"; } };
class FlyingRobot : public Flyable, public Robot {};   // inherits from BOTH
// FlyingRobot fr; fr.fly(); fr.compute();  -- both work

Multilevel inheritance

class Animal { public: void eat() { cout << "eats\n"; } };
class Mammal : public Animal { public: void walk() { cout << "walks\n"; } };
class Dog : public Mammal { public: void bark() { cout << "barks\n"; } };
// Dog has ALL THREE: eat(), walk(), bark() -- inherited through the whole chain

Hierarchical inheritance

class Shape { public: virtual double area() = 0; };
class Circle : public Shape { /* ... */ };
class Square : public Shape { /* ... */ };
// Circle and Square are independent siblings, both derived from Shape

Hybrid inheritance (and the diamond problem)

class A { public: int x; };
class B : public A {};
class C : public A {};
class D : public B, public C {};   // PROBLEM: D has TWO copies of A::x -- which one does D::x refer to?

// Fix: virtual inheritance
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};   // NOW: only ONE shared copy of A::x

Why the diamond problem happens

D inherits from both B and C, and both B and C separately inherit from A. Without virtual, the compiler creates two independent sub-objects of A inside D — one via the B path, one via the C path — so d.x is genuinely ambiguous. virtual inheritance tells the compiler to share a single A sub-object no matter how many paths lead to it.

Important MCQs

  1. One derived class inheriting from two or more base classes is called:
    • a) Single inheritance b) Multiple inheritance c) Hierarchical inheritance d) Multilevel inheritance
  2. A chain like Animal → Mammal → Dog is an example of:
    • a) Hierarchical b) Multilevel c) Hybrid d) Single
  3. One base class with several independent derived classes (e.g., Shape → Circle, Square) is:
    • a) Multilevel b) Hierarchical c) Multiple d) Hybrid
  4. The "diamond problem" arises specifically in:
    • a) Single inheritance b) Multilevel inheritance c) Hybrid inheritance (combining multiple + multilevel/hierarchical) d) Hierarchical inheritance only
  5. The diamond problem is resolved in C++ using:
    • a) static b) virtual inheritance c) friend d) const

✅ Self-Test Questions (with Answers)

Q1. Give a real-world example (not from this page) for each of the 5 forms of inheritance.

Ans: Taking a banking / university domain rather than the animal and shape examples above:

FormStructureFresh example
SingleOne base, one derivedAccount -> SavingsAccount
MultipleOne derived, two or more basesTeachingAssistant inherits Student and Employee
MultilevelChain of three or morePerson -> Employee -> Manager
HierarchicalOne base, several siblingsAccount -> Savings, Current, FixedDeposit
HybridTwo or more forms combinedPerson -> Student and Employee, both -> TeachingAssistant (a diamond)
// 1. SINGLE
class Account { protected: double balance; };
class SavingsAccount : public Account { double rate; };

// 2. MULTIPLE -- two unrelated bases
class Printer { public: void print(); };
class Scanner { public: void scan();  };
class Photocopier : public Printer, public Scanner { };   // does both

// 3. MULTILEVEL -- a chain
class Person   { protected: string name; };
class Employee : public Person   { protected: double salary; };
class Manager  : public Employee { int teamSize; };       // has name, salary, teamSize

// 4. HIERARCHICAL -- independent siblings from one base
class Current      : public Account { double overdraft; };
class FixedDeposit : public Account { int termMonths;   };

// 5. HYBRID -- hierarchical + multiple => the DIAMOND
class Student  : virtual public Person { string rollNo; };
class Staff    : virtual public Person { double pay;    };
class TeachingAssistant : public Student, public Staff { };
// 'virtual' ensures ONE shared Person sub-object, not two copies of 'name'

Points to add in an exam answer: the TeachingAssistant case is the most instructive, because a TA genuinely is both a student and a member of staff, yet must have only one name and one ID — which is exactly why the diamond problem arises and why virtual inheritance is the remedy. Note also that hybrid is not a sixth independent mechanism but simply any combination of the other forms, and that C++ supports all five directly, whereas Java restricts classes to single inheritance and achieves the multiple case through interfaces.

Q2. Why does the diamond problem specifically require hybrid (not just multiple) inheritance to occur?

Ans: Because the ambiguity comes not from having two bases, but from those two bases sharing a common ancestor. Multiple inheritance alone is perfectly safe when the bases are unrelated — a FlyingRobot inheriting from Flyable and Robot has one copy of each, with no duplication and nothing to be ambiguous about. The diamond only forms when multiple inheritance is combined with hierarchical inheritance (one base, two children) and multilevel inheritance (the grandchild) — that combination is exactly what "hybrid" means. The shape is: A at the top, B and C both deriving from A, and D deriving from both B and C, so that two independent inheritance paths lead from D back to the same A.

// SAFE multiple inheritance -- bases are unrelated, no common ancestor
class Flyable { public: void fly(); };
class Robot   { public: void compute(); };
class FlyingRobot : public Flyable, public Robot { };   // no ambiguity whatsoever

// THE DIAMOND -- hybrid: hierarchical (A->B, A->C) + multiple (B,C -> D)
class A { public: int x = 0; void greet(); };
class B : public A { };
class C : public A { };
class D : public B, public C { };

int main() {
    D d;
    // d.x = 5;        // ERROR: request for member 'x' is ambiguous
    // d.greet();      // ERROR: 'A' is an ambiguous base of 'D'
    d.B::x = 5;        // legal but ugly workaround: name the path explicitly
    d.C::x = 9;        // a DIFFERENT variable -- two separate A sub-objects exist
    cout << sizeof(D); // larger than expected: A's data is stored TWICE
}

The two harms are therefore: (1) ambiguity — d.x could mean the A reached through B or the one through C, so the compiler refuses; and (2) duplication — D genuinely contains two complete A sub-objects, wasting memory and, worse, allowing them to hold different values for what should logically be one attribute. The fix is virtual inheritance (class B : virtual public A), which makes all paths share a single A sub-object.

MCQ trap: "the diamond problem is caused by multiple inheritance" is only half right, and papers often offer both options — the precise trigger is hybrid inheritance, i.e. multiple inheritance from classes that share a common ancestor.

Q3. What keyword resolves the diamond problem, and where does it need to be placed?

Ans: The keyword is virtual, used in the form of virtual inheritance. The critical detail — and the part examiners check — is where it goes: on the intermediate classes' inheritance from the common base (B and C), not on the class where the ambiguity appears (D), and not on the base A itself. The reason is that B and C are the classes that each contribute a copy of A; declaring their inheritance virtual tells the compiler to share a single A sub-object however many paths reach it.

class A { public: int x = 1; };
class B : virtual public A { };    // 'virtual' goes HERE
class C : virtual public A { };    // and HERE
class D : public B, public C { };  // NOT here -- D is where the problem showed up,
                                   // but not where the fix belongs
int main() {
    D d;
    d.x = 5;                       // unambiguous now -- exactly ONE A sub-object
    cout << d.B::x << " " << d.C::x;   // 5 5   <- both paths see the SAME x
}

virtual public A and public virtual A are equivalent — the order of the two keywords does not matter.

Consequences worth mentioning for full marks:

  • Construction of a virtual base is the responsibility of the most-derived class. D's constructor must initialise A directly; the calls written in B and C for A are ignored. If A has no default constructor, D must list A(...) explicitly, or the code will not compile.
  • The virtual base is constructed first of all, before B and C.
  • There is a small run-time cost: objects carry an extra pointer (a vbase offset) so the shared sub-object can be located, and sizeof grows slightly.
  • The design must be decided up front: you cannot retro-fit virtual inheritance at D after B and C are written non-virtually.

MCQ trap: this virtual has nothing to do with virtual functions. The same keyword serves two unrelated purposes — virtual inheritance shares a base sub-object, while a virtual function enables run-time polymorphism through the vtable.

📌 Sample & Repeated FPSC Questions (2016–2026)

2024, Paper I, Q7 (1 mark, MCQ) — Which language does not allow for inheritance in all four forms?

  • A) Kotlin
  • B) Java
  • C) C++
  • D) None of these

Correct answer: B. Java does not support multiple inheritance of classes (one of the classical forms — single, multilevel, hierarchical, multiple), allowing multiple inheritance only through interfaces. C++ supports all four forms directly for classes.

MCQ Trap: don't confuse "doesn't support multiple inheritance of classes" with "doesn't support multiple inheritance at all" — Java achieves the same effect via interfaces, it just doesn't allow it between concrete classes.

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

MCQs

2024 P-I · Q7. Which language does not allow for inheritance in all four forms?

  • (A) Kotlin
  • (B) Java ✅
  • (C) C++
  • (D) None of these
  • Answer: (B) Java (the intended key).
  • Why: the four forms are single, multilevel, hierarchical and multiple. C++ supports all four. Java classes cannot extend more than one class, so multiple inheritance of classes is missing. It is only possible through interfaces.
  • Note: Kotlin has the same restriction, so the question is weak, and Java is the expected key.