subclass


Concept: subclasses

A subclass, also known as a derived class, is a class that inherits properties and behaviors from another class, called the base class or parent class. Subclassing is a fundamental concept in object-oriented programming, allowing for code reuse and the creation of hierarchical relationships between classes.

Key Characteristics

Example 1. Basic Inheritance

#include <iostream>
#include <string>

class Animal {
protected:
    std::string name;

public:
    Animal(const std::string& n) : name(n) {}

    void eat() const {
        std::cout << name << " is eating." << std::endl;
    }

    virtual void makeSound() const {
        std::cout << name << " makes a sound." << std::endl;
    }
};

class Dog : public Animal {
public:
    Dog(const std::string& n) : Animal(n) {}

    void wagTail() const {
        std::cout << name << " is wagging its tail." << std::endl;
    }

    void makeSound() const override {
        std::cout << name << " barks: Woof!" << std::endl;
    }
};

int main() {
    Animal animal("Generic Animal");
    Dog dog("Buddy");

    animal.eat();
    animal.makeSound();

    dog.eat();  // Inherited from Animal
    dog.makeSound();  // Overridden method
    dog.wagTail();  // Dog-specific method

    return 0;
}

Explanation:

Example 2: Protected Members and Constructor Inheritance

#include <iostream>
#include <string>

class Shape {
protected:
    double area;

public:
    Shape() : area(0) {}

    virtual void calculateArea() = 0;

    void displayArea() const {
        std::cout << "Area: " << area << std::endl;
    }
};

class Circle : public Shape {
private:
    double radius;

public:
    Circle(double r) : radius(r) {}

    void calculateArea() override {
        area = 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double length, width;

public:
    Rectangle(double l, double w) : length(l), width(w) {}

    void calculateArea() override {
        area = length * width;
    }
};

int main() {
    Circle circle(5);
    Rectangle rectangle(4, 6);

    circle.calculateArea();
    rectangle.calculateArea();

    std::cout << "Circle ";
    circle.displayArea();

    std::cout << "Rectangle ";
    rectangle.displayArea();

    return 0;
}

Explanation:

Example 3: Multiple Inheritance

#include <iostream>
#include <string>

class Flyable {
public:
    virtual void fly() const {
        std::cout << "Flying..." << std::endl;
    }
};

class Swimmable {
public:
    virtual void swim() const {
        std::cout << "Swimming..." << std::endl;
    }
};

class Duck : public Flyable, public Swimmable {
private:
    std::string name;

public:
    Duck(const std::string& n) : name(n) {}

    void introduce() const {
        std::cout << "I'm " << name << " the duck." << std::endl;
    }

    // Optionally override inherited methods
    void fly() const override {
        std::cout << name << " is flying." << std::endl;
    }

    void swim() const override {
        std::cout << name << " is swimming." << std::endl;
    }
};

int main() {
    Duck duck("Donald");

    duck.introduce();
    duck.fly();
    duck.swim();

    return 0;
}

Explanation:

Example 4: Virtual Inheritance to Solve Diamond Problem

#include <iostream>

class Animal {
protected:
    std::string name;

public:
    Animal(const std::string& n) : name(n) {}
    virtual void eat() const {
        std::cout << name << " is eating." << std::endl;
    }
};

class Mammal : virtual public Animal {
public:
    Mammal(const std::string& n) : Animal(n) {}
    void breathe() const {
        std::cout << name << " is breathing." << std::endl;
    }
};

class WingedAnimal : virtual public Animal {
public:
    WingedAnimal(const std::string& n) : Animal(n) {}
    void flap() const {
        std::cout << name << " is flapping wings." << std::endl;
    }
};

class Bat : public Mammal, public WingedAnimal {
public:
    Bat(const std::string& n) : Animal(n), Mammal(n), WingedAnimal(n) {}
    void echo() const {
        std::cout << name << " is using echolocation." << std::endl;
    }
};

int main() {
    Bat bat("Bruce");
    bat.eat();    // From Animal
    bat.breathe(); // From Mammal
    bat.flap();    // From WingedAnimal
    bat.echo();    // Bat's own method

    return 0;
}

Explanation:

Additional Considerations

  1. Access Specifiers: public, protected, and private inheritance affect how base class members are accessed in the derived class.

  2. Virtual Functions: Use virtual functions in the base class for runtime polymorphism.

  3. Abstract Classes: Classes with pure virtual functions can't be instantiated and serve as interfaces for derived classes.

  4. Override Keyword: Use the override keyword to explicitly indicate that a function is meant to override a base class function.

  5. Constructors and Destructors: Derived class constructors must call base class constructors, and destructors are called in reverse order of construction.

Summary

Subclasses in C++ provide a powerful mechanism for code reuse and hierarchical design:

  1. They inherit properties and behaviors from base classes.
  2. Allow for method overriding and extension of base class functionality.
  3. Support single and multiple inheritance.
  4. Enable polymorphic behavior through virtual functions.
  5. Can access protected members of the base class.

Key points to remember:

Best practices:

Subclasses are a fundamental concept in object-oriented programming in C++, providing a way to create specialized classes based on more general ones, promoting code reuse and logical organization of code.

Related

Previous Page | Course Schedule | Course Content