Разница между частным, публичным и защищенным наследованием

StackOverflow https://stackoverflow.com/questions/860339

Вопрос

В чем разница между public, private, и protected наследование в C ++?Все вопросы, которые я нашел на SO, касаются конкретных случаев.

Это было полезно?

Решение

Чтобы ответить на этот вопрос, я хотел бы сначала описать средства доступа участника своими словами.Если вы уже знаете это, перейдите к заголовку "далее:".

Есть три способа доступа, о которых я знаю: public, protected и private.

Пусть:

class Base {
    public:
        int publicMember;
    protected:
        int protectedMember;
    private:
        int privateMember;
};
  • Все, что осознается Base также осознает , что Base содержит publicMember.
  • Только дети (и их дети) знают, что Base содержит protectedMember.
  • Никто , кроме Base осознает privateMember.

Под "осознает" я подразумеваю "признает существование и, таким образом, имеет возможность доступа".

Далее:

То же самое происходит с публичным, частным и защищенным наследованием.Давайте рассмотрим класс Base и класс Child который наследуется от Base.

  • Если наследство является public, все , что известно о Base и Child также осознает , что Child наследуется от Base.
  • Если наследство является protected, только Child, и его дети осознают, что они наследуют от Base.
  • Если наследство является private, никто иной , как Child осведомлен о наследовании.

Другие советы

class A 
{
public:
    int x;
protected:
    int y;
private:
    int z;
};

class B : public A
{
    // x is public
    // y is protected
    // z is not accessible from B
};

class C : protected A
{
    // x is protected
    // y is protected
    // z is not accessible from C
};

class D : private A    // 'private' is default for classes
{
    // x is private
    // y is private
    // z is not accessible from D
};

ВАЖНОЕ ПРИМЕЧАНИЕ:Все классы B, C и D содержат переменные x, y и z.Это просто вопрос доступа.

Об использовании защищенного и частного наследования вы могли бы прочитать здесь.

Ограничение видимости наследования приведет к тому, что код не сможет увидеть, что какой-то класс наследует другой класс:Неявные преобразования из производного в базовое не будут работать, и static_cast переход от базового к производному тоже не сработает.

Только члены / друзья класса могут видеть частное наследование, и только члены / друзья и производные классы могут видеть защищенное наследование.

публичный наследование

  1. ЭТО-наследство.Кнопка - это окно, и в любом месте, где требуется окно, кнопка тоже может быть передана.

    class button : public window { };
    

защищенный наследование

  1. Защищенный реализованный с точки зрения.Редко бывает полезным.Используется в boost::compressed_pair для получения из пустых классов и экономии памяти с использованием оптимизации пустого базового класса (приведенный ниже пример не использует шаблон, чтобы оставаться в точке):

    struct empty_pair_impl : protected empty_class_1 
    { non_empty_class_2 second; };
    
    struct pair : private empty_pair_impl {
      non_empty_class_2 &second() {
        return this->second;
      }
    
      empty_class_1 &first() {
        return *this; // notice we return *this!
      }
    };
    

Частное наследование

  1. Реализованный-с-точки зрения-из.Базовый класс используется только для реализации производного класса.Полезно с признаками, и если размер имеет значение (пустые признаки, которые содержат только функции, будут использовать оптимизацию пустого базового класса).Часто сдерживание тем не менее, это лучшее решение.Размер строк имеет решающее значение, поэтому здесь это часто встречается

    template<typename StorageModel>
    struct string : private StorageModel {
    public:
      void realloc() {
        // uses inherited function
        StorageModel::realloc();
      }
    };
    

публичный Участник

  1. Совокупный

    class pair {
    public:
      First first;
      Second second;
    };
    
  2. Средства доступа

    class window {
    public:
        int getWidth() const;
    };
    

защищенный Участник

  1. Предоставление расширенного доступа к производным классам

    class stack {
    protected:
      vector<element> c;
    };
    
    class window {
    protected:
      void registerClass(window_descriptor w);
    };
    

Частное Участник

  1. Сохраните детали реализации

    class window {
    private:
      int width;
    };
    

Обратите внимание, что приведение в стиле C намеренно позволяет приводить производный класс к защищенному или частному базовому классу определенным и безопасным способом, а также выполнять приведение в другом направлении.Этого следует избегать любой ценой, поскольку это может сделать код зависимым от деталей реализации, но при необходимости вы можете воспользоваться этим приемом.

Это связано с тем, как общедоступные члены базового класса предоставляются из производного класса.

  • общедоступные -> общедоступные члены базового класса будут общедоступными (обычно по умолчанию)
  • защищенный -> открытые члены базового класса будут защищены
  • частные -> общедоступные члены базового класса будут закрытыми

Как указывает litb, публичное наследование - это традиционное наследование, которое вы увидите в большинстве языков программирования.То есть он моделирует отношения "ЕСТЬ-А".Частное наследование, что-то AFAIK, характерное для C ++, является отношением, "РЕАЛИЗОВАННЫМ В ТЕРМИНАХ".То есть вы хотите, чтобы использование общедоступный интерфейс в производном классе, но не хотите, чтобы пользователь производного класса имел доступ к этому интерфейсу.Многие утверждают, что в этом случае вы должны агрегировать базовый класс, то есть вместо того, чтобы использовать базовый класс в качестве частной базы, make в члене derived, чтобы повторно использовать функциональность базового класса.

Эти три ключевых слова также используются в совершенно другом контексте для указания модель наследования видимости.

В этой таблице собраны все возможные комбинации объявления компонента и модели наследования, представляющие результирующий доступ к компонентам, когда подкласс полностью определен.

enter image description here

Приведенная выше таблица интерпретируется следующим образом (взгляните на первую строку).:

если компонент является объявленный как публичный и его класс таков унаследованный как публичный результирующий доступ является публичный.

Пример:

 class Super {
    public:      int p;
    private:     int q;
    protected:   int r;
 };

 class Sub : private Super {};

 class Subsub : public Sub {};

Результирующий доступ к переменным p, q, r в классе Подсубъект является Нет.

Другой пример:

class Super {
    private:     int x;
    protected:   int y;
    public:      int z;
 };
class Sub : protected Super {};

Результирующий доступ к переменным y, z в классе SUB является защищенный и для переменной x является Нет.

Более подробный пример:

class Super {
private:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};
int main(void) {
    Super object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Теперь давайте определим подкласс:

class Sub : Super { };

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get());
    cout << object.get() << endl;
    return 0;
}

Определенный класс с именем Sub, который является подклассом класса с именем Super или это Sub класс является производным от Super класс.В Sub класс не вводит ни новых переменных, ни новых функций.Означает ли это, что любой объект Sub класс наследует все черты после Super класс, являющийся фактически копией Super объекты класса’?

НЕТ.Это не так.

Если мы скомпилируем следующий код, мы не получим ничего, кроме ошибок компиляции, говорящих о том, что put и get методы недоступны.Почему?

Когда мы опускаем спецификатор видимости, компилятор предполагает, что мы собираемся применить так называемый частное наследование.Это означает , что все публичный компоненты суперкласса превращаются в Частное доступ, частные компоненты суперкласса вообще не будут доступны.Следовательно, это означает, что вам не разрешается использовать последнее внутри подкласса.

Мы должны сообщить компилятору, что хотим сохранить ранее использованную политику доступа.

class Sub : public Super { };

Не позволяйте ввести себя в заблуждение:это не означает, что частные компоненты класса Super (например, переменная storage) превратятся в общедоступные несколько волшебным образом. Частное компоненты останутся Частное, публичный останется публичный.

Объекты в Sub класс может делать "почти" то же самое, что и их старшие братья и сестры, созданные на основе Super класс. "Почти" потому что факт принадлежности к подклассу также означает , что класс потерял доступ к закрытым компонентам суперкласса.Мы не можем написать функцию - член для Sub класс, который мог бы напрямую манипулировать переменной хранилища.

Это очень серьезное ограничение.Есть ли какое-нибудь обходное решение?

ДА.

Третий уровень доступа называется защищенный.Ключевое слово protected означает, что компонент, отмеченный им ведет себя как общедоступный при использовании любым из подклассов и выглядит как закрытый для остального мира. -- Это верно только для публично наследуемых классов (таких как Суперкласс в нашем примере). --

class Super {
protected:
    int storage;
public:
    void put(int val) { storage = val;  }
    int  get(void)    { return storage; }
};

class Sub : public Super {
public:
    void print(void) {cout << "storage = " << storage;}
};

int main(void) {
    Sub object;

    object.put(100);
    object.put(object.get() + 1);
    object.print();
    return 0;
}

Как вы видите в примере кода, мы добавили новую функциональность к Sub класс, и это делает одну важную вещь: он обращается к переменной хранилища из суперкласса.

Это было бы невозможно, если бы переменная была объявлена как закрытая.В основной области видимости функции переменная в любом случае остается скрытой, поэтому, если вы напишете что-нибудь вроде:

object.storage = 0;

Компилятор сообщит вам, что это error: 'int Super::storage' is protected.

Наконец, последняя программа выдаст следующий результат:

storage = 101
Member in base class : Private   Protected   Public   

Тип наследования :             Объект , унаследованный как:

Private            :   Inaccessible   Private     Private   
Protected          :   Inaccessible   Protected   Protected  
Public             :   Inaccessible   Protected   Public

1) Публичное Наследование:

a.Закрытые члены базового класса недоступны в производном классе.

b.Защищенные члены базового класса остаются защищенными в производном классе.

c.Открытые члены базового класса остаются открытыми в производном классе.

Таким образом, другие классы могут использовать общедоступные члены базового класса через производный class object.

2) Защищенное Наследование:

a.Закрытые члены базового класса недоступны в производном классе.

b.Защищенные члены базового класса остаются защищенными в производном классе.

c.Открытые члены базового класса тоже становятся защищенными членами производного класса.

Таким образом, другие классы не могут использовать общедоступные члены базового класса через объект производного класса;но они доступны для подкласса Derived.

3) Частное Наследование:

a.Закрытые члены базового класса недоступны в производном классе.

b.Защищенные и общедоступные члены базового класса становятся закрытыми членами производного класса.

Таким образом, никакие члены базового класса не могут быть доступны другим классам через объект производного класса, поскольку они являются закрытыми в производном классе.Таким образом, даже подкласс производного класс не может получить к ним доступ.

Публичное наследование моделирует отношение IS-A.С

class B {};
class D : public B {};

каждый D является B.

Частное наследование моделирует отношение IS-IMPLEMENTED-USING (или как там это называется).С

class B {};
class D : private B {};

a D является не a B, но каждый D использует свои B в его реализации.Частное наследование всегда можно устранить, используя вместо него сдерживание:

class B {};
class D {
  private: 
    B b_;
};

Это D, тоже может быть реализован с помощью B, в данном случае используя его b_.Сдерживание - это менее тесная связь между типами, чем наследование, поэтому в целом ему следует отдать предпочтение.Иногда использование сдерживания вместо частного наследования не так удобно, как частное наследование.Часто это неубедительное оправдание лени.

Я не думаю, что кто-нибудь знает, что protected модели наследования.По крайней мере, я пока не видел никакого убедительного объяснения.

Если вы публично наследуете от другого класса, все знают, что вы наследуете, и любой пользователь может использовать вас полиморфно через указатель базового класса.

Если вы наследуете защищенным образом, только ваши дочерние классы смогут использовать вас полиморфно.

Если вы наследуете конфиденциально, только вы сами сможете выполнять методы родительского класса.

Что в основном символизирует знания, которыми обладают остальные классы о ваших отношениях с вашим родительским классом

Защищенные элементы данных могут быть доступны любым классам, наследуемым от вашего класса.Однако участники с личными данными не могут этого сделать.Допустим, у нас есть следующее:

class MyClass {
    private:
        int myPrivateMember;    // lol
    protected:
        int myProtectedMember;
};

Из вашего расширения к этому классу, ссылающемуся this.myPrivateMember не сработает.Однако, this.myProtectedMember уилл.Значение по-прежнему инкапсулировано, поэтому, если у нас есть экземпляр этого класса, вызываемый myObj, тогда myObj.myProtectedMember не будет работать, поэтому по своим функциям он аналогичен закрытому элементу данных.

Accessors    | Base Class | Derived Class | World
—————————————+————————————+———————————————+———————
public       |      y     |       y       |   y
—————————————+————————————+———————————————+———————
protected    |      y     |       y       |   n
—————————————+————————————+———————————————+———————
private      |            |               |    
  or         |      y     |       n       |   n
no accessor  |            |               |

y: accessible
n: not accessible

Основанный на это пример для java...Я думаю, что маленькая таблица стоит тысячи слов :)

Краткие сведения:

  • Частное:никто не может видеть это, кроме как внутри класса
  • Защищенный:Частные + производные классы могут это видеть
  • Публичный:мир может видеть это

При наследовании вы можете (на некоторых языках) изменить тип защиты элемента данных в определенном направлении, напримерот защищенного к общедоступному.

Частное:

К закрытым членам базового класса могут быть доступны только члены этого базового класса .

Публичный:

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

Защищенный:

К защищенным членам базового класса могут быть доступны как члены базового класса, так и члены его производного класса.


Короче говоря:

Частное:База

защищенный:базовый + производный

публичный:базовый + производный + любой другой член

Я нашел простой ответ и поэтому подумал о том, чтобы опубликовать его и для моего дальнейшего использования.

Это из ссылок http://www.learncpp.com/cpp-tutorial/115-inheritance-and-access-specifiers/

class Base
{
public:
    int m_nPublic; // can be accessed by anybody
private:
    int m_nPrivate; // can only be accessed by Base member functions (but not derived classes)
protected:
    int m_nProtected; // can be accessed by Base member functions, or derived classes.
};

class Derived: public Base
{
public:
    Derived()
    {
        // Derived's access to Base members is not influenced by the type of inheritance used,
        // so the following is always true:

        m_nPublic = 1; // allowed: can access public base members from derived class
        m_nPrivate = 2; // not allowed: can not access private base members from derived class
        m_nProtected = 3; // allowed: can access protected base members from derived class
    }
};

int main()
{
    Base cBase;
    cBase.m_nPublic = 1; // allowed: can access public members from outside class
    cBase.m_nPrivate = 2; // not allowed: can not access private members from outside class
    cBase.m_nProtected = 3; // not allowed: can not access protected members from outside class
}

По сути, это защита доступа общедоступных и защищенных членов базового класса в производном классе.При общедоступном наследовании производный класс может видеть общедоступные и защищенные элементы базы.При частном наследовании этого не может быть.При использовании protected производный класс и любые производные от него классы могут их видеть.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top