Я запутался в значении модификаторов доступа в отношении наследования. В чем разница между наследованием с ключевыми словами private
, protected
и public
?
Что такое спецификаторы доступа? Должен ли я наследовать с закрытыми, защищенными или публичными?
Ответ 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-реализовано-в-терминах" - так что вам не нужно придерживаться интерфейса суперкласса, вы просто повторно используете реализация.