Module 03: Inheritance
Key Concepts:
- Base and derived classes
- Access specifiers with inheritance
- Constructor/destructor chaining
- Member access in inheritance
- Multiple inheritance (Diamond Problem)
Why Inheritance? (The Problem: Code Duplication)
Section titled “Why Inheritance? (The Problem: Code Duplication)”Imagine you’re writing a game with different robot types:
// Without inheritance - lots of duplicated code!class ClapTrap { std::string _name; int _hitPoints; int _energyPoints; void attack(std::string target); void takeDamage(int amount); void beRepaired(int amount);};
class ScavTrap { std::string _name; // Duplicated! int _hitPoints; // Duplicated! int _energyPoints; // Duplicated! void attack(std::string target); // Similar logic! void takeDamage(int amount); // Duplicated! void beRepaired(int amount); // Duplicated! void guardGate(); // Only this is unique};
class FragTrap { std::string _name; // Duplicated AGAIN! // ... same duplication problem};This is painful:
- Same code written multiple times
- Bug fixes must be applied in multiple places
- Adding features means editing many classes
Inheritance solves this: Extract common code into a base class, then derive specialized classes that add unique features:
class ClapTrap { /* common code */ };class ScavTrap : public ClapTrap { void guardGate(); }; // Adds guardGateclass FragTrap : public ClapTrap { void highFivesGuys(); }; // Adds highFivesUnderstanding Inheritance Syntax (For Beginners)
Section titled “Understanding Inheritance Syntax (For Beginners)”This module introduces class inheritance. Here are the new operators and syntax you’ll encounter:
The : Operator (Inheritance Declaration)
Section titled “The : Operator (Inheritance Declaration)”class Derived : public Base { }; // Derived inherits from Base:(colon) introduces the inheritance list- It says “this class IS-A kind of that class”
publicmeans base class public members stay public in derived class- Read it as: “Derived inherits publicly from Base”
The virtual Keyword (Inheritance Modifier)
Section titled “The virtual Keyword (Inheritance Modifier)”class Middle : virtual public Base { }; // Virtual inheritancevirtualin inheritance solves the “diamond problem”- Without
virtual, a class inheriting from two classes that share a base gets TWO copies of the base - With
virtual, only ONE copy of the base class exists - Use this when multiple inheritance creates a diamond shape in the class hierarchy
Accessing Base Class Members with ::
Section titled “Accessing Base Class Members with ::”ClapTrap::attack(target); // Call base class versionBase::operator=(other); // Call base assignment operatorClassName::lets you explicitly call a base class method- This is necessary when you’ve overridden (redefined) a method in the derived class
- Use it to access the base class implementation from the derived class
The using Declaration
Section titled “The using Declaration”using ScavTrap::attack; // Bring ScavTrap's attack into current scopeusing Base::print; // Bring ALL Base::print overloads into scopeusingimports names from another scope into the current scope- In inheritance, it brings base class methods into the derived class scope
- Useful when you override some overloads but want to keep others accessible
- Without
using Base::print, if you overrideprint()(no parameters), theprint(int)overload becomes hidden
The protected Access Specifier
Section titled “The protected Access Specifier”class Base {protected: // Accessible in this class AND derived classes int _hitPoints;public: // Accessible everywhere void attack();};protectedis betweenprivateandpublic- Private: Only the class itself can access
- Protected: The class AND its derived classes can access
- Public: Everyone can access
- Use
protectedfor members that derived classes need to use but outsiders shouldn’t access
Constructor Chaining with Initialization List
Section titled “Constructor Chaining with Initialization List”ScavTrap(std::string name) : ClapTrap(name) { // Base constructor called first, then this runs}- The initialization list (
:before the{) chains to the base constructor ClapTrap(name)calls the base class constructor with the name parameter- Base class constructor runs BEFORE derived class constructor body
- You MUST call the base constructor if the base has no default constructor
Why base runs first? A derived object contains the base object “inside” it. The base part must be fully constructed before the derived part can use it. Think of building a house: you need the foundation (base) before you can add the upper floors (derived).
Calling Base Copy Constructor
Section titled “Calling Base Copy Constructor”ScavTrap(const ScavTrap& other) : ClapTrap(other) { // other is a ScavTrap, which IS-A ClapTrap}ClapTrap(other)calls the base copy constructor- Even though
otheris aScavTrap, it can be passed asClapTrap&because inheritance IS-A relationship - This copies the base class members; you copy derived class members in the body
1. Basic Inheritance
Section titled “1. Basic Inheritance”Syntax
Section titled “Syntax”class Base {protected: std::string _name; int _hitPoints;
public: Base(std::string name); void attack(const std::string& target);};
class Derived : public ClapTrap { // Derived inherits from ClapTrappublic: Derived(std::string name); void specialAbility();};The “Is-A” Relationship
Section titled “The “Is-A” Relationship”┌─────────────────────────────────────────────────────────────────┐│ Inheritance = "IS-A" Relationship │├─────────────────────────────────────────────────────────────────┤│ ││ Visual Model: ││ ┌───────────────┐ ││ │ ClapTrap │ ←── Base (parent) class ││ │ ───────── │ Defines common attributes ││ │ _name │ and behaviors ││ │ _hitPoints │ ││ │ attack() │ ││ └───────┬───────┘ ││ │ ││ │ "IS-A" ││ │ ││ ┌────┴────┐ ││ ▼ ▼ ││ ┌────────┐ ┌────────┐ ││ │ScavTrap│ │FragTrap│ ←── Derived (child) classes ││ │ IS-A │ │ IS-A │ Inherit from ClapTrap ││ │ClapTrap│ │ClapTrap│ + add specializations ││ │────────│ │────────│ ││ │guardG- │ │highF- │ ││ │ate() │ │ives() │ ││ └────────┘ └────────┘ ││ ││ Memory Layout: ││ ┌──────────────────────────────────────────────────────┐ ││ │ ClapTrap portion (inherited) │ ││ │ ┌─────────────┐ │ ││ │ │ _name │ │ ││ │ │ _hitPoints │ │ ││ │ │ _energy │ ←── Base class data │ ││ │ └─────────────┘ │ ││ ├──────────────────────────────────────────────────────┤ ││ │ ScavTrap portion (added) │ ││ │ ┌─────────────┐ │ ││ │ │ _gateMode │ ←── Derived class data │ ││ │ └─────────────┘ │ ││ └──────────────────────────────────────────────────────┘ ││ ││ Read it as: "ScavTrap IS-A ClapTrap" ││ - A ScavTrap can do everything a ClapTrap can do ││ - Plus ScavTrap adds its own special abilities ││ - Use inheritance for "is-a" relationships ││ - Use composition for "has-a" relationships ││ │└─────────────────────────────────────────────────────────────────┘What Gets Inherited?
Section titled “What Gets Inherited?”| Member Type | Inherited? |
|---|---|
| Public members | Yes (as public) |
| Protected members | Yes (as protected) |
| Private members | No (exist but inaccessible) |
| Constructors | No (but can be called) |
| Destructors | No (but automatically called) |
2. Access Specifiers in Inheritance
Section titled “2. Access Specifiers in Inheritance”Public Inheritance (Most Common)
Section titled “Public Inheritance (Most Common)”class Derived : public Base { // Base public -> Derived public // Base protected -> Derived protected // Base private -> inaccessible};Protected Inheritance
Section titled “Protected Inheritance”class Derived : protected Base { // Base public -> Derived protected // Base protected -> Derived protected // Base private -> inaccessible};Private Inheritance
Section titled “Private Inheritance”class Derived : private Base { // Base public -> Derived private // Base protected -> Derived private // Base private -> inaccessible};Visual Summary
Section titled “Visual Summary” In Derived Class Outside DerivedPublic Inheritance: Base public public accessible Base protected protected not accessible Base private - -
Protected Inheritance: Base public protected not accessible Base protected protected not accessible Base private - -
Private Inheritance: Base public private not accessible Base protected private not accessible Base private - -3. Constructor/Destructor Chaining
Section titled “3. Constructor/Destructor Chaining”Construction Order
Section titled “Construction Order”- Base class constructor runs FIRST
- Derived class constructor runs SECOND
class ClapTrap {public: ClapTrap(std::string name) { std::cout << "ClapTrap constructor" << std::endl; }};
class ScavTrap : public ClapTrap {public: ScavTrap(std::string name) : ClapTrap(name) { std::cout << "ScavTrap constructor" << std::endl; }};
// Creating ScavTrap prints:// ClapTrap constructor// ScavTrap constructorConstructor Chaining Flowchart
Section titled “Constructor Chaining Flowchart”┌─────────────────────────────────────────────────────────────────┐│ Constructor Execution Order in Inheritance │├─────────────────────────────────────────────────────────────────┤│ ││ Construction Order (Top-Down): ││ ┌────────────────────────────────────────────────────────┐ ││ │ │ ││ │ ┌─────────────┐ │ ││ │ │ 1. BASE │ ◄── ClapTrap constructor runs FIRST │ ││ │ │ CONSTRUCTOR │ Initialize inherited members │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────┐ │ ││ │ │ 2. MEMBER │ ◄── Member variables constructors │ ││ │ │ CONSTRUCTORS│ (if any members are objects) │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────┐ │ ││ │ │ 3. DERIVED │ ◄── ScavTrap constructor body runs │ ││ │ │ CONSTRUCTOR │ Initialize own members │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ [OBJECT READY] │ ││ │ │ ││ └────────────────────────────────────────────────────────┘ ││ ││ Code Example Flow: ││ ┌────────────────────────────────────────────────────────┐ ││ │ │ ││ │ ScavTrap s("Scavvy"); │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌──────────────────────────────────────┐ │ ││ │ │ ScavTrap::ScavTrap(string name) │ │ ││ │ │ : ClapTrap(name) ◄── calls base │ │ ││ │ │ { │ │ ││ │ │ // Base already constructed │ │ ││ │ │ _hitPoints = 100; ◄── modify │ │ ││ │ │ } │ │ ││ │ └──────────────────────────────────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌──────────────────────────────────────┐ │ ││ │ │ ClapTrap::ClapTrap(string name) { │ │ ││ │ │ _name = name; │ │ ││ │ │ _hitPoints = 10; │ │ ││ │ │ } │ │ ││ │ │ ↓ completes first │ │ ││ │ └──────────────────────────────────────┘ │ ││ │ │ │ ││ │ ▼ returns to derived │ ││ │ [Derived constructor body executes] │ ││ │ │ ││ └────────────────────────────────────────────────────────┘ ││ ││ Destruction Order (Bottom-Up - REVERSE): ││ ┌────────────────────────────────────────────────────────┐ ││ │ │ ││ │ ┌─────────────┐ │ ││ │ │ 1. DERIVED │ ◄── ScavTrap destructor runs FIRST │ ││ │ │ DESTRUCTOR │ Clean up own resources │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────┐ │ ││ │ │ 2. MEMBER │ ◄── Member destructors │ ││ │ │ DESTRUCTORS │ │ ││ │ └──────┬──────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌─────────────┐ │ ││ │ │ 3. BASE │ ◄── ClapTrap destructor runs LAST │ ││ │ │ DESTRUCTOR │ Clean up inherited resources │ ││ │ └─────────────┘ │ ││ │ │ ││ └────────────────────────────────────────────────────────┘ ││ ││ Remember: Construction is TOP-DOWN (base → derived) ││ Destruction is BOTTOM-UP (derived → base) ││ │└─────────────────────────────────────────────────────────────────┘Destruction Order (REVERSE)
Section titled “Destruction Order (REVERSE)”- Derived class destructor runs FIRST
- Base class destructor runs SECOND
class ClapTrap {public: ~ClapTrap() { std::cout << "ClapTrap destructor" << std::endl; }};
class ScavTrap : public ClapTrap {public: ~ScavTrap() { std::cout << "ScavTrap destructor" << std::endl; }};
// Destroying ScavTrap prints:// ScavTrap destructor// ClapTrap destructorCalling Base Constructor
Section titled “Calling Base Constructor”class ScavTrap : public ClapTrap {public: // MUST call base constructor in initialization list ScavTrap(std::string name) : ClapTrap(name) { // Base is already constructed here _hitPoints = 100; // Override base values _energyPoints = 50; _attackDamage = 20; }};Copy Constructor in Derived Classes
Section titled “Copy Constructor in Derived Classes”The copy constructor must explicitly call the base class copy constructor:
class ScavTrap : public ClapTrap {public: // Copy constructor - call base copy constructor ScavTrap(const ScavTrap& other) : ClapTrap(other) { // other is a ScavTrap, which IS-A ClapTrap // Base class copy constructor handles inherited members std::cout << "ScavTrap copy constructor" << std::endl; }};Assignment Operator in Derived Classes
Section titled “Assignment Operator in Derived Classes”The assignment operator should call the base class assignment operator:
class ScavTrap : public ClapTrap {public: ScavTrap& operator=(const ScavTrap& other) { if (this != &other) { // Call base class assignment operator ClapTrap::operator=(other);
// Assign derived class members (if any) // _derivedMember = other._derivedMember; } return *this; }};Complete Orthodox Canonical Form for Derived Class
Section titled “Complete Orthodox Canonical Form for Derived Class”class ScavTrap : public ClapTrap {public: // Default constructor ScavTrap() : ClapTrap() { _hitPoints = 100; _energyPoints = 50; _attackDamage = 20; }
// Parameterized constructor ScavTrap(std::string name) : ClapTrap(name) { _hitPoints = 100; _energyPoints = 50; _attackDamage = 20; }
// Copy constructor ScavTrap(const ScavTrap& other) : ClapTrap(other) { // Derived members copied here if any }
// Assignment operator ScavTrap& operator=(const ScavTrap& other) { if (this != &other) { ClapTrap::operator=(other); } return *this; }
// Destructor ~ScavTrap() { // Derived cleanup (base destructor called automatically) }};4. Overriding Functions
Section titled “4. Overriding Functions”Basic Override
Section titled “Basic Override”class ClapTrap {public: void attack(const std::string& target) { std::cout << "ClapTrap " << _name << " attacks " << target << std::endl; }};
class ScavTrap : public ClapTrap {public: void attack(const std::string& target) { std::cout << "ScavTrap " << _name << " attacks " << target << std::endl; }};
ClapTrap clap("Clappy");ScavTrap scav("Scavvy");
clap.attack("enemy"); // "ClapTrap Clappy attacks enemy"scav.attack("enemy"); // "ScavTrap Scavvy attacks enemy"Calling Base Class Function
Section titled “Calling Base Class Function”class ScavTrap : public ClapTrap {public: void attack(const std::string& target) { // Call base class version ClapTrap::attack(target);
// Add extra behavior std::cout << "...with extra ScavTrap power!" << std::endl; }};Name Shadowing
Section titled “Name Shadowing”When a derived class declares a member with the same name as a base class member, it shadows (hides) the base class member:
class Base {public: void print() { std::cout << "Base" << std::endl; } void print(int x) { std::cout << "Base: " << x << std::endl; }};
class Derived : public Base {public: void print() { std::cout << "Derived" << std::endl; } // print(int) is now HIDDEN!};
Derived d;d.print(); // OK: "Derived"d.print(42); // ERROR: print(int) is shadowed!d.Base::print(42); // OK: explicit scope resolutionThe using Declaration
Section titled “The using Declaration”Bring base class members into derived class scope:
class DiamondTrap : public ScavTrap, public FragTrap {public: // Bring ScavTrap's attack into DiamondTrap's scope using ScavTrap::attack;
// Now DiamondTrap::attack() calls ScavTrap::attack()};
// Also useful to un-hide overloaded functions:class Derived : public Base {public: using Base::print; // Bring ALL Base::print overloads void print() { std::cout << "Derived" << std::endl; }};
Derived d;d.print(); // OK: "Derived"d.print(42); // OK: Base::print(int) is now visible5. Protected Members
Section titled “5. Protected Members”Why Protected?
Section titled “Why Protected?”class ClapTrap {private: std::string _name; // Only ClapTrap can access
protected: int _hitPoints; // ClapTrap AND derived classes can access
public: void display(); // Everyone can access};
class ScavTrap : public ClapTrap {public: void specialAttack() { // _name = "X"; // ERROR: private in ClapTrap _hitPoints -= 10; // OK: protected is accessible }};Access Summary
Section titled “Access Summary”class Base {private: int _private; // Only Base methodsprotected: int _protected; // Base + Derived methodspublic: int _public; // Everyone};6. ClapTrap Exercise Structure
Section titled “6. ClapTrap Exercise Structure”ex00: ClapTrap (Base Class)
Section titled “ex00: ClapTrap (Base Class)”class ClapTrap {protected: std::string _name; int _hitPoints; // 10 int _energyPoints; // 10 int _attackDamage; // 0
public: ClapTrap(std::string name); ClapTrap(const ClapTrap& other); ClapTrap& operator=(const ClapTrap& other); ~ClapTrap();
void attack(const std::string& target); void takeDamage(unsigned int amount); void beRepaired(unsigned int amount);};ex01: ScavTrap (Inherits ClapTrap)
Section titled “ex01: ScavTrap (Inherits ClapTrap)”class ScavTrap : public ClapTrap {public: ScavTrap(std::string name); ScavTrap(const ScavTrap& other); ScavTrap& operator=(const ScavTrap& other); ~ScavTrap();
void attack(const std::string& target); // Override void guardGate(); // New ability};
// Constructor must initialize base with different values:// _hitPoints = 100, _energyPoints = 50, _attackDamage = 20ex02: FragTrap (Inherits ClapTrap)
Section titled “ex02: FragTrap (Inherits ClapTrap)”class FragTrap : public ClapTrap {public: FragTrap(std::string name); FragTrap(const FragTrap& other); FragTrap& operator=(const FragTrap& other); ~FragTrap();
void highFivesGuys(); // New ability};
// _hitPoints = 100, _energyPoints = 100, _attackDamage = 307. Multiple Inheritance and the Diamond Problem (ex03)
Section titled “7. Multiple Inheritance and the Diamond Problem (ex03)”The Diamond Problem
Section titled “The Diamond Problem” ClapTrap / \ ScavTrap FragTrap \ / DiamondTrapWithout virtual inheritance:
- DiamondTrap has TWO copies of ClapTrap
- Ambiguity: which ClapTrap’s _name?
Virtual Inheritance Solution
Section titled “Virtual Inheritance Solution”class ClapTrap { // ...};
class ScavTrap : virtual public ClapTrap { // ^^^^^^^ KEY WORD};
class FragTrap : virtual public ClapTrap { // ^^^^^^^ KEY WORD};
class DiamondTrap : public ScavTrap, public FragTrap { // Now only ONE ClapTrap subobject};DiamondTrap Implementation
Section titled “DiamondTrap Implementation”class DiamondTrap : public ScavTrap, public FragTrap {private: std::string _name; // Same variable name as ClapTrap::_name
public: DiamondTrap(std::string name); ~DiamondTrap();
// Uses ScavTrap's attack using ScavTrap::attack;
void whoAmI();};
DiamondTrap::DiamondTrap(std::string name) : ClapTrap(name + "_clap_name"), // Initialize virtual base ScavTrap(name), FragTrap(name), _name(name){ // Attributes from FragTrap except energy from ScavTrap _hitPoints = FragTrap::_hitPoints; // or just 100 _energyPoints = ScavTrap::_energyPoints; // or just 50 _attackDamage = FragTrap::_attackDamage; // or just 30}
void DiamondTrap::whoAmI() { std::cout << "I am " << _name << std::endl; std::cout << "My ClapTrap name is " << ClapTrap::_name << std::endl;}Virtual Base Class Construction
Section titled “Virtual Base Class Construction”With virtual inheritance, the MOST DERIVED class must initialize the virtual base:
DiamondTrap::DiamondTrap(std::string name) : ClapTrap(name + "_clap_name"), // DiamondTrap initializes ClapTrap ScavTrap(name), // ScavTrap's ClapTrap init is ignored FragTrap(name), // FragTrap's ClapTrap init is ignored _name(name){}8. Best Practices
Section titled “8. Best Practices”When to Use Inheritance
Section titled “When to Use Inheritance”- “Is-a” relationship: ScavTrap IS A ClapTrap
- Code reuse: Derived classes share base class code
- Polymorphism: Treat derived as base (Module 04)
When NOT to Use Inheritance
Section titled “When NOT to Use Inheritance”- “Has-a” relationship: Use composition instead
- Just for code reuse with unrelated classes
- When relationship doesn’t make semantic sense
Common Mistakes
Section titled “Common Mistakes”- Forgetting to call base constructor
- Wrong destruction order expectations
- Accessing private (not protected) base members
- Not using virtual inheritance for diamond
Quick Reference
Section titled “Quick Reference”// Basic inheritanceclass Derived : public Base { };
// Constructor chainingDerived(args) : Base(base_args), _member(val) { }
// Override functionvoid Derived::method() { Base::method(); /* extra */ }
// Virtual inheritance (diamond)class Middle : virtual public Base { };