Наследование

Глава 4. Объектно-ориентированное программирование в C++ #

4.2 Наследование в C++ #

1. Базовые принципы наследования #

Наследование - это механизм, позволяющий создавать новые классы на основе существующих, сохраняя и расширяя их функциональность.

// Базовый класс
class Animal {
protected:
    std::string name;

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

    void eat() {
        std::cout << name << " ест." << std::endl;
    }

    virtual void makeSound() {
        std::cout << "Какой-то звук" << std::endl;
    }
};

// Производный класс
class Dog : public Animal {
public:
    // Конструктор производного класса
    Dog(std::string n) : Animal(n) {}

    // Переопределение метода базового класса
    void makeSound() override {
        std::cout << name << " лает: Гав-гав!" << std::endl;
    }

    // Новый метод только для Dog
    void fetch() {
        std::cout << name << " приносит палку." << std::endl;
    }
};

int main() {
    Dog Rex("Рекс");
    Rex.eat();       // Метод из базового класса
    Rex.makeSound(); // Переопределенный метод
    Rex.fetch();     // Метод производного класса

    return 0;
}

2. Виды наследования #

C++ поддерживает три основных типа наследования:

Публичное наследование (public) #

class Base {
public:
    int publicField;
protected:
    int protectedField;
private:
    int privateField;
};

// Публичное наследование сохраняет модификаторы доступа базового класса
class Derived : public Base {
    void example() {
        publicField;     // Остается public
        protectedField;  // Остается protected
        // privateField; // Недоступно
    }
};

Защищенное наследование (protected) #

class Derived : protected Base {
    void example() {
        publicField;     // Теперь protected
        protectedField;  // Остается protected
        // privateField; // Недоступно
    }
};

Приватное наследование (private) #

class Derived : private Base {
    void example() {
        publicField;     // Теперь private
        protectedField;  // Теперь private
        // privateField; // Недоступно
    }
};

3. Множественное наследование #

C++ позволяет наследоваться от нескольких базовых классов:

class Engine {
public:
    void start() {
        std::cout << "Двигатель запущен" << std::endl;
    }
};

class Wheel {
public:
    void rotate() {
        std::cout << "Колеса вращаются" << std::endl;
    }
};

// Множественное наследование
class Car : public Engine, public Wheel {
public:
    void drive() {
        start();  // Метод из Engine
        rotate(); // Метод из Wheel
        std::cout << "Машина едет" << std::endl;
    }
};

int main() {
    Car myCar;
    myCar.drive();
    return 0;
}

4. Виртуальное наследование #

Решает проблему “ромбовидного наследования”:

class Animal {
protected:
    std::string name;
public:
    Animal(std::string n) : name(n) {}
};

// Виртуальное наследование
class Mammal : virtual public Animal {
public:
    Mammal(std::string n) : Animal(n) {}
    void breathe() {
        std::cout << name << " дышит" << std::endl;
    }
};

class Flyable : virtual public Animal {
public:
    Flyable(std::string n) : Animal(n) {}
    void fly() {
        std::cout << name << " летит" << std::endl;
    }
};

// Разрешаем конфликт инициализации базового класса
class Bat : public Mammal, public Flyable {
public:
    Bat(std::string n) : Animal(n), Mammal(n), Flyable(n) {}
};

int main() {
    Bat batman("Летучая мышь");
    batman.breathe(); // Метод из Mammal
    batman.fly();     // Метод из Flyable
    return 0;
}

5. Ключевое слово override #

Ключевое слово override помогает предотвратить ошибки при переопределении виртуальных методов:

class Shape {
public:
    // Виртуальный метод в базовом классе
    virtual double calculateArea() const {
        return 0.0;
    }

    virtual ~Shape() {} // Виртуальный деструктор
};

class Circle : public Shape {
private:
    double radius;

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

    // Корректное переопределение с использованием override
    double calculateArea() const override {
        return 3.14159 * radius * radius;
    }
};

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

public:
    Rectangle(double w, double h) : width(w), height(h) {}

    // Еще одно переопределение
    double calculateArea() const override {
        return width * height;
    }
};

// Демонстрация полиморфизма
void printArea(const Shape& shape) {
    std::cout << "Площадь: " << shape.calculateArea() << std::endl;
}

int main() {
    Circle circle(5.0);
    Rectangle rect(4.0, 6.0);

    printArea(circle); // Полиморфный вызов
    printArea(rect);   // Полиморфный вызов

    return 0;
}

Заключение #

Наследование в C++ - мощный механизм объектно-ориентированного программирования, который позволяет:

  • Создавать иерархии классов
  • Переиспользовать код
  • Реализовывать полиморфное поведение
  • Моделировать сложные взаимосвязи между объектами

Ключевые моменты:

  • Различные виды наследования
  • Множественное наследование
  • Виртуальное наследование
  • Использование override для безопасного переопределения методов