Menu
Coddy logo textTech

Уровни доступа при наследовании

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 49 из 104.

Выбранный тип наследования влияет на то, как члены базового класса доступны в производном классе. C++ предлагает три варианта: наследование public, protected и private.

Вот как каждый тип изменяет доступ к членам:

Base членpublic inheritanceprotected inheritanceprivate inheritance
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateinaccessibleinaccessibleinaccessible
class Base {
public:
    int pub;
protected:
    int prot;
private:
    int priv;
};

class PublicDerived : public Base {
    // pub является public, prot является protected, priv недоступен
};

class ProtectedDerived : protected Base {
    // pub является protected, prot является protected, priv недоступен
};

class PrivateDerived : private Base {
    // pub является private, prot является private, priv недоступен
};

Public inheritance моделирует отношения «является» и является наиболее распространённым видом. Dog — это Animal, поэтому внешний код может обращаться с ним как с Animal.

protected и private inheritance model отношения «реализовано через». Они скрывают интерфейс базового класса от внешнего кода и полезны, когда нужно повторно использовать реализацию, не раскрывая связь наследования. При private inheritance даже последующие derived классы теряют доступ к исходным членам базового класса.

challenge icon

Задание

Легко

Давайте рассмотрим, как разные типы наследования влияют на доступность членов, создав простую иерархию устройств. Вы создадите базовый Device class и три производных класса, каждый с использованием отдельного типа наследования, чтобы на практике увидеть, как public-, protected- и private-наследование преобразуют доступ к членам.

Вы организуете код в двух файлах:

  • Device.h: определите базовый Device class с тремя членами, имеющими разные уровни доступа:
    • public std::string model
    • protected int serialNumber
    • private int internalCode (по умолчанию установлено значение 999)
    • public method showModel(), который печатает: Model: <model>

    Затем создайте три производных класса, каждый из которых наследуется от Device с использованием отдельного типа наследования:

    • PublicDevice с использованием public inheritance: добавьте method displaySerial(), который печатает: Serial: <serialNumber>
    • ProtectedDevice с использованием protected inheritance: добавьте method displaySerial(), который печатает: Serial: <serialNumber>
    • PrivateDevice с использованием private inheritance: добавьте method displaySerial(), который печатает: Serial: <serialNumber>

    Каждый производный класс должен иметь Constructor, принимающий название модели и серийный номер, передающий модель в базовый класс и устанавливающий серийный номер.

  • main.cpp: прочитайте два входных значения (каждое в отдельной строке):
    1. Название модели (строка)
    2. Серийный номер (целое число)

    Create по одному object каждого производного типа с одинаковыми входными значениями. Затем продемонстрируйте различия в доступе:

    Для PublicDevice:

    • Вызовите showModel() напрямую у object (это работает, поскольку public inheritance сохраняет его public)
    • Получите доступ к model напрямую и напечатайте: Direct model access: <model>
    • Вызовите displaySerial()

    Для ProtectedDevice и PrivateDevice:

    • Only вызовите displaySerial() (унаследованные showModel() и model больше не являются public и недоступны извне)

    Формат вывода:

    --- PublicDevice ---
    Model: <model>
    Direct model access: <model>
    Serial: <serial>
    --- ProtectedDevice ---
    Serial: <serial>
    --- PrivateDevice ---
    Serial: <serial>

Например, для входных значений Laptop и 12345:

--- PublicDevice ---
Model: Laptop
Direct model access: Laptop
Serial: 12345
--- ProtectedDevice ---
Serial: 12345
--- PrivateDevice ---
Serial: 12345

Обратите внимание, что только PublicDevice разрешает external access к унаследованным public членам. Другие типы наследования скрывают интерфейс базового класса от внешнего кода, однако производные классы всё ещё могут получать доступ к protected членам internally через собственные методы.

Попробуйте сами

#include <iostream>
#include <string>
#include "Device.h"

using namespace std;

int main() {
    // Прочитать ввод
    string modelName;
    int serialNum;
    
    getline(cin, modelName);
    cin >> serialNum;
    
    // TODO: Создайте объекты каждого производного типа с входными значениями
    // PublicDevice pubDev(modelName, serialNum);
    // ProtectedDevice protDev(modelName, serialNum);
    // PrivateDevice privDev(modelName, serialNum);
    
    // TODO: Demonstrate PublicDevice access
    cout << "--- PublicDevice ---" << endl;
    // - Вызовите showModel() напрямую на объекте
    // - Access model directly and print: Direct model access: <model>
    // - Вызовите displaySerial()
    
    // TODO: Demonstrate ProtectedDevice access
    cout << "--- ProtectedDevice ---" << endl;
    // - Вызовите только displaySerial() (showModel и model не доступны публично)
    
    // TODO: Demonstrate PrivateDevice access
    cout << "--- PrivateDevice ---" << endl;
    // - Вызовите только displaySerial() (showModel и model не доступны публично)
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++