Menu
Coddy logo textTech

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

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

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

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

Член базового классапубличное наследованиезащищенное наследованиезакрытое наследование
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateнедоступеннедоступеннедоступен
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 недоступен
};

Публичное наследование моделирует отношения типа «является» (is-a) и является наиболее распространенным. Dog является Animal, поэтому внешний код может обращаться с ним как с таковым.

Защищенное (protected) и закрытое (private) наследование моделируют отношения «реализовано посредством» (implemented-in-terms-of). Они скрывают интерфейс базового класса от внешнего кода, что полезно, когда вы хотите повторно использовать реализацию, не раскрывая отношения наследования. При закрытом наследовании даже последующие производные классы теряют доступ к членам исходного базового класса.

challenge icon

Задание

Легко

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

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

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

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

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

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

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

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

    Для PublicDevice:

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

    Для ProtectedDevice и PrivateDevice:

    • Вызовите только displaySerial() (унаследованные showModel() и model больше не доступны публично извне)

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

    --- 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 разрешает внешний доступ к унаследованным публичным членам. Другие типы наследования скрывают интерфейс базового класса от внешнего кода, но производные классы все равно могут обращаться к защищенным членам внутри через свои собственные методы.

Шпаргалка

C++ предлагает три типа наследования, которые управляют тем, как члены базового класса доступны в производных классах:

Член базового классаpublic наследованиеprotected наследованиеprivate наследование
publicpublicprotectedprivate
protectedprotectedprotectedprivate
privateнедоступеннедоступеннедоступен
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) моделирует отношение "является" (is-a) и встречается чаще всего. Внешний код может обращаться к публичным членам базового класса через производный класс.

Защищенное и закрытое наследование (Protected and private inheritance) моделируют отношение "реализовано посредством" (implemented-in-terms-of). Они скрывают интерфейс базового класса от внешнего кода. При закрытом наследовании даже последующие производные классы теряют доступ к исходным членам базового класса.

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

#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: Продемонстрируйте доступ к PublicDevice
    cout << "--- PublicDevice ---" << endl;
    // - Вызовите showModel() напрямую у объекта
    // - Обратитесь к model напрямую и выведите: Direct model access: <model>
    // - Вызовите displaySerial()
    
    // TODO: Продемонстрируйте доступ к ProtectedDevice
    cout << "--- ProtectedDevice ---" << endl;
    // - Вызовите только displaySerial() (showModel и model не являются публично доступными)
    
    // TODO: Продемонстрируйте доступ к PrivateDevice
    cout << "--- PrivateDevice ---" << endl;
    // - Вызовите только displaySerial() (showModel и model не являются публично доступными)
    
    return 0;
}
quiz iconПроверьте себя

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

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