📚

Understanding Inheritance in C++

Dec 30, 2024

Lecture Notes: Inheritance in C++

Introduction to Inheritance

  • Inheritance is a feature of OOP that allows the extension/enhancement of functionality from a base class to a derived class.
  • Syntax for inheritance in C++:
    class DerivedClass : <list of base classes>
    
    • <list of base classes> is a comma-separated list of base classes, each prefixed by an access level specifier: public, protected, or private.

Access Level Specifiers

  • Default access level:
    • private for classes
    • public for structs
  • Example:
    class Derived : Base; // Same as class Derived : private Base
    struct Derived : Base; // Same as struct Derived : public Base
    

Usage Recommendations

  • Prefer using structs for Plain Old Data (POD) or record structures.
  • Use classes for encapsulation and polymorphism.

Inheritance Modes

  • Inheritance modes define access levels to base class members in derived classes:
    • class Derived : Base defaults to private
    • class Derived : protected Base
    • class Derived : public Base
  • Public and protected members of a base class are accessible in derived classes, but private members are not directly accessible.

Multiple Inheritance

  • Multiple inheritance is possible but can complicate the design.
  • Example of multiple inheritance:
    class Person {};
    class Father : public Person {};
    class Mother : public Person {};
    class Child : public Father, public Mother {};
    

Mixins

  • Mixins are used for adding functionality, following the HAS A relationship.
  • If functionality (e.g., weight) applies to multiple classes, use a mixin class:
    class WeightMixin {
        float weight_;
    public:
        float get_weight() const { return this->weight_; }
        void update_weight(const float weight) { this->weight_ = weight; }
    };
    

Initialization Order

  • When initializing a derived class, base classes are initialized first.
  • Destruction occurs in the reverse order of initialization.
  • Example:
    class Base {
    public:
        Base() { std::cout << "Initialized Base" << std::endl; }
        ~Base() { std::cout << "Destroying Base" << std::endl; }
    };
    class Derived : public Base {
    public:
        Derived() { std::cout << "Initialized Derived" << std::endl; }
        ~Derived() { std::cout << "Destroying Derived" << std::endl; }
    };
    

Practical Exercise

  • Implement derived classes from Animal: Cat and Dog.
  • Overload methods to demonstrate inheritance:
    class Animal {
    protected:
        std::string name;
    public:
        Animal(std::string _name) : name(_name) {}
        void eat(std::string food) {
            std::cout << name << " eats " << food << std::endl;
        }
    };
    
    • Example usage:
      • Garfield the cat eats milk and is printed with weight.
      • Milo the dog eats steak and is printed with weight.

Conclusion

  • Inheritance allows code reuse by extending base class functionalities.
  • Use mixins carefully to add shared functionalities without direct duplication.
  • Pay attention to inheritance modes and private member accessibility.