У чому різниця між
public
,private
іprotected
успадкування в C ++?
Усі питання, які я знайшов у програмі SO, стосуються конкретних випадків.
У чому різниця між
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
знає ніхто інший, окрім як.SomeBase
- це як жорсткий спосіб складання анонімного члена типу SomeBase
. Цей, як і будь-який інший член, має специфікатор доступу, який здійснює той же контроль над зовнішнім доступом.
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
від бази до похідного також не буде працювати.
Лише члени / друзі класу можуть бачити приватне успадкування, і лише члени / друзі та похідні класи можуть бачити захищене спадкування.
публічна спадщина
IS-A спадщина. Кнопка - це вікно, і в будь-якому місці, де потрібне вікно, також можна пропустити кнопку.
class button : public window { };
захищене спадщину
Захищені реалізовані в умовах терміни. Рідко корисна. Використовується 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!
}
};
приватне успадкування
Впроваджено в терміни. Використання базового класу лише для реалізації похідного класу. Корисно для ознак і якщо значення має значення (порожні ознаки, які містять лише функції, використовуватимуть оптимізацію порожнього базового класу). Однак часто стримування є кращим рішенням. Розмір для рядків є критичним, тому це часто зустрічається використання
template<typename StorageModel>
struct string : private StorageModel {
public:
void realloc() {
// uses inherited function
StorageModel::realloc();
}
};
громадський член
Сукупність
class pair {
public:
First first;
Second second;
};
Аксесуари
class window {
public:
int getWidth() const;
};
захищений член
Забезпечення розширеного доступу для похідних класів
class stack {
protected:
vector<element> c;
};
class window {
protected:
void registerClass(window_descriptor w);
};
приватний член
Зберігайте деталі реалізації
class window {
private:
int width;
};
Зауважте, що касти в стилі C цілеспрямовано дозволяють передати похідний клас захищеному або приватному базовому класу визначеним та безпечним чином, а також в інший бік. Цього слід уникати будь-якою ціною, оскільки це може зробити код залежним від деталей реалізації - але, якщо необхідно, ви можете скористатися цією методикою.
Ці три ключові слова також використовуються у зовсім іншому контексті для визначення моделі успадкування видимості .
У цій таблиці зібрані всі можливі комбінації декларації компонента та моделі успадкування, що представляють отриманий доступ до компонентів, коли підклас повністю визначений.
Таблиця, подана вище, інтерпретується таким чином (подивіться на перший рядок):
якщо компонент оголошений в якості громадськості та її клас успадковуються , як громадськості в результаті доступу є громадськістю .
Приклад:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
В результаті доступ до змінних p
, q
, r
в класі Subsub НЕ ніхто .
Ще один приклад:
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 (на зразок змінної пам’яті) перетворяться у публічні дещо чарівним чином. Приватні компоненти залишаться приватними , державні - публічними .
Об'єкти Sub
класу можуть робити «майже» ті ж речі, що і їхні старші брати та сестри, створені з Super
класу. "Майже" тому, що факт існування підкласу також означає, що клас втратив доступ до приватних компонентів надкласу . Ми не можемо написати функцію члена Sub
класу, яка могла б безпосередньо маніпулювати змінною зберігання.
Це дуже серйозне обмеження. Чи є якесь вирішення?
Так .
Третій рівень доступу називається захищеним . Захищене ключове слово означає, що позначений ним компонент поводиться як загальнодоступний при використанні будь-якого з підкласів і схожий на приватний на інший світ . - Це справедливо лише для публічно успадкованих класів (як, наприклад, клас Super у нашому прикладі) -
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
класу, і це робить одне важливе: він отримує доступ до змінної пам'яті з класу Super .
Це було б неможливо, якби змінна була оголошена приватною. У основній області функцій змінна все одно залишається прихованою, тому якщо ви пишете щось на зразок:
object.storage = 0;
Компілятор повідомить вам, що це error: 'int Super::storage' is protected
.
Нарешті, остання програма дасть такий вихід:
storage = 101
Це стосується того, як громадські члени базового класу піддаються впливу похідного класу.
Як вказує litb, публічне успадкування - це традиційне успадкування, яке ви побачите в більшості мов програмування. Тобто це моделює відносини "IS-A". Приватне успадкування, що є властивим для C ++, є AFAIK - це відносини "ВПРОВАДЖЕНО У УМОВИ". Тобто ви хочете використовувати публічний інтерфейс у похідному класі, але не хочете, щоб користувач похідного класу мав доступ до цього інтерфейсу. Багато хто стверджує, що в цьому випадку вам слід об'єднати базовий клас, тобто замість того, щоб базовий клас був приватним, вносити в член похідний, щоб повторно використовувати функціональність базового класу.
Member in base class : Private Protected Public
Тип успадкування : об’єкт успадковується як :
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
1) Громадське успадкування :
а. Приватні члени базового класу недоступні в класі Похідні.
б. Захищені члени базового класу залишаються захищеними в класі похідних.
c. Громадські члени базового класу залишаються відкритими в класі похідних.
Отже, інші класи можуть використовувати публічних членів класу Base через об’єкт класу Derived.
2) Захищене спадкування :
а. Приватні члени базового класу недоступні в класі Похідні.
б. Захищені члени базового класу залишаються захищеними в класі похідних.
c. Громадські члени базового класу теж стають захищеними членами класу Derived.
Отже, інші класи не можуть використовувати публічних членів класу Base через об’єкт Derived class; але вони доступні для підкласу Похідне.
3) Приватне успадкування :
а. Приватні члени базового класу недоступні в класі Похідні.
б. Захищені та громадські члени базового класу стають приватними членами класу "Похідні".
Отже, жоден член класу Base не може отримати доступ до інших класів через об’єкт класу Derived, оскільки вони є приватними у класі Derived. Отже, навіть підклас класу Derived не може отримати до них доступ.
Суспільна модель успадкування відносин IS-A. З
class B {};
class D : public B {};
кожен D
- a B
.
Приватні моделі успадкування стосунків, які ВИМОГАЮТЬ-ВИКОРИСТОВУЮТЬСЯ (або як це називається). З
class B {};
class D : private B {};
D
це НЕB
, але кожен D
використовує B
в своїй реалізації. Приватне успадкування завжди можна усунути, використовуючи замість цього:
class B {};
class D {
private:
B b_;
};
Це D
також можна реалізувати, використовуючи B
, у цьому випадку, його b_
. Утримання - це менш тісний зв'язок між типами, ніж спадкування, тому загалом слід віддати перевагу. Іноді використовувати стримування замість приватного успадкування не так зручно, як приватне успадкування. Часто це кульгавий привід за те, що лінивий.
Я не думаю, що хтось знає, які protected
моделі успадкування. Принаймні, я ще не бачив жодного переконливого пояснення.
D
приватно походить від D
, воно може змінювати віртуальні функції B
. (Якщо, наприклад, B
це інтерфейс для спостерігачів, тоді він D
може реалізовувати його і переходити this
до функцій, що вимагають аукціону інтерфейсу, не маючи змоги використовувати його D
як спостерігач.) Також, він D
може вибірково зробити членів B
доступними в його інтерфейсі, роблячи це using B::member
. Обидва синтаксично незручно реалізовувати, коли B
є членом.
protected
Спадщина Я вважаю корисним з virtual
базовим класом та protected
ctor:struct CommonStuff { CommonStuff(Stuff*) {/* assert !=0 */ } }; struct HandlerMixin1 : protected virtual CommonStuff { protected: HandlerMixin1() : CommonStuff(nullptr) {} /*...*/ }; struct Handler : HandlerMixin1, ... { Handler(Stuff& stuff) : CommonStuff(&stuff) {} };
Якщо ви успадковуєте публічно від іншого класу, всі знають, що ви успадковуєте, і ви можете використовувати поліморфно будь-хто через покажчик базового класу.
Якщо ви успадковуватимете захищеність, то лише ваші діти-класи зможуть використовувати вас поліморфно.
Якщо ви успадковуєте приватно, лише ви самі зможете виконувати методи батьківського класу.
Що в основному символізує знання інших класів про ваші стосунки з батьківським класом
До захищених членів даних можна отримати доступ будь-яких класів, які успадковують ваш клас. Учасники приватних даних, однак, не можуть. Скажімо, у нас є наступне:
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
}
По суті це захист доступу для публіки та захищених членів базового класу у похідному класі. Маючи державну спадщину, похідний клас може бачити публічних та захищених членів бази. При приватному успадкуванні це не може. З захищеним, похідним класом і будь-якими класами, що випливають з цього, можна побачити їх.