Подтвердить что ты не робот

Что такое спецификаторы доступа? Должен ли я наследовать с закрытыми, защищенными или публичными?

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

4b9b3361

Ответ 1

что такое спецификации доступа?

Для класса /struct/Union в С++ существует 3 access specifiers. Эти спецификаторы доступа определяют, каким образом могут быть доступны члены класса. Конечно, любой член класса доступен в этом классе (внутри любой функции-члена того же класса). Переходя к типу спецификаторов доступа, они:

Public. Члены, объявленные как Public, доступны извне класса через объект класса.

Защищенный. Элементы, объявленные как Защищенные, доступны извне класса НО только в классе, полученном из него.

Частный. Эти члены доступны только из класса. Доступ к внешнему доступу не разрешен.

Пример исходного кода:

class MyClass
{
    public:
        int a;
    protected:
        int b;
    private:
        int c;
};

int main()
{
    MyClass obj;
    obj.a = 10;     //Allowed
    obj.b = 20;     //Not Allowed, gives compiler error
    obj.c = 30;     //Not Allowed, gives compiler error
}

Наследование и спецификации доступа

Наследование в С++ может быть одним из следующих типов:

  • Private Наследование
  • Public Наследование
  • Protected наследование

Ниже приведены правила доступа членов к каждому из них:

Первое и самое важное правило Private члены класса никогда не доступны нигде, кроме членов одного и того же класса.

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

Все Public члены базового класса становятся Public. Члены производного класса &
Все члены Protected базового класса становятся Protected членами производного класса.

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

Пример кода:

Class Base
{
    public:
        int a;
    protected:
        int b;
    private:
        int c;
};

class Derived:public Base
{
    void doSomething()
    {
        a = 10;  //Allowed 
        b = 20;  //Allowed
        c = 30;  //Not Allowed, Compiler Error
    }
};

int main()
{
    Derived obj;
    obj.a = 10;  //Allowed
    obj.b = 20;  //Not Allowed, Compiler Error
    obj.c = 30;  //Not Allowed, Compiler Error

}

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

Все Public члены базового класса становятся Private членами класса Derived &
Все члены Protected базового класса становятся Private членами производного класса.

Пример кода:

Class Base
{
    public:
      int a;
    protected:
      int b;
    private:
      int c;
};

class Derived:private Base   //Not mentioning private is OK because for classes it  defaults to private 
{
    void doSomething()
    {
        a = 10;  //Allowed 
        b = 20;  //Allowed
        c = 30;  //Not Allowed, Compiler Error
    }
};

class Derived2:public Derived
{
    void doSomethingMore()
    {
        a = 10;  //Not Allowed, Compiler Error, a is private member of Derived now
        b = 20;  //Not Allowed, Compiler Error, b is private member of Derived now
        c = 30;  //Not Allowed, Compiler Error
    }
};

int main()
{
    Derived obj;
    obj.a = 10;  //Not Allowed, Compiler Error
    obj.b = 20;  //Not Allowed, Compiler Error
    obj.c = 30;  //Not Allowed, Compiler Error

}

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

Все Public члены базового класса становятся Protected. Члены производного класса &
Все члены Protected базового класса становятся Protected членами производного класса.

Пример кода:

Class Base
{
    public:
        int a;
    protected:
        int b;
    private:
        int c;
};

class Derived:protected Base  
{
    void doSomething()
    {
        a = 10;  //Allowed 
        b = 20;  //Allowed
        c = 30;  //Not Allowed, Compiler Error
    }
};

class Derived2:public Derived
{
    void doSomethingMore()
    {
        a = 10;  //Allowed, a is protected member inside Derived & Derived2 is public derivation from Derived, a is now protected member of Derived2
        b = 20;  //Allowed, b is protected member inside Derived & Derived2 is public derivation from Derived, b is now protected member of Derived2
        c = 30;  //Not Allowed, Compiler Error
    }
};

int main()
{
    Derived obj;
    obj.a = 10;  //Not Allowed, Compiler Error
    obj.b = 20;  //Not Allowed, Compiler Error
    obj.c = 30;  //Not Allowed, Compiler Error
}

Помните, что одни и те же правила доступа применяются к классам и членам вниз по иерархии наследования.


Важные замечания:

- Спецификация доступа для каждого класса не для каждого объекта

Обратите внимание, что спецификация доступа С++ работает на основе каждого класса, а не на основе объекта.
Хорошим примером этого является то, что в конструкторе копирования или в функции оператора присваивания копий можно получить доступ ко всем членам передаваемого объекта.

- Производный класс может обращаться только к членам собственного базового класса

Рассмотрим следующий пример кода:

class Myclass
{ 
    protected: 
       int x; 
}; 

class derived : public Myclass
{
    public: 
        void f( Myclass& obj ) 
        { 
            obj.x = 5; 
        } 
};

int main()
{
    return 0;
}

Он дает ошибку компиляции:

prog.cpp: 4: error: 'int Myclass:: x защищен

Поскольку производный класс может получить доступ только к членам своего собственного базового класса. Обратите внимание, что передаваемый здесь объект obj никак не связан с функцией класса derived, к которой он обращается, это совсем другой объект и, следовательно, функция-член derived не может получить доступ к своим членам.


Что такое friend? Как friend влияет на правила спецификации доступа?

Вы можете объявить функцию или класс как friend другого класса. Когда вы это делаете, правила спецификации доступа не применяются к friend ed class/function. Класс или функция могут получить доступ ко всем членам этого конкретного класса.

Итак, friend break encapsulation?

Нет, они этого не делают, напротив, они усиливают инкапсуляцию!

friend корабль используется для обозначения <сильной > преднамеренной сильной связи между двумя объектами.
Если существует особая связь между двумя объектами, так что вам нужен доступ к другим членам Private или Protected, но вы не хотите, чтобы каждый имел доступ с помощью спецификатора доступа Public, тогда вы должен использовать корабль friend.

Ответ 2

Объяснение Скотта Мейерса в Эффективном C++ может помочь понять, когда их использовать:

Публичное наследование должно моделировать отношение "is-a", тогда как частное наследование должно использоваться для "is-реализовано-в-терминах" - так что вам не нужно придерживаться интерфейса суперкласса, вы просто повторно используете реализация.