В чем разница между public
, private
и protected
наследованием в С++? Все вопросы, которые я нашел на SO, касаются конкретных случаев.
Разница между частным, общественным и защищенным наследованием
Ответ 1
Чтобы ответить на этот вопрос, я хотел бы сначала описать членство элемента в своих собственных словах. Если вы уже знаете это, перейдите к заголовку "next:".
Есть три устройства доступа, о которых я знаю: 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
о наследовании.
Ответ 2
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. Это просто вопрос доступа.
Об использовании защищенного и частного наследования вы можете прочитать здесь.
Ответ 3
Ограничение видимости наследования сделает код неспособным увидеть, что какой-либо класс наследует другой класс: неявные преобразования из полученного в базу не будут работать, а static_cast
от базы до производной не будет работать ни,
Только члены/друзья класса могут видеть личное наследование, и только члены/друзья и производные классы могут видеть защищенное наследование.
public Наследование
-
Наследование 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; };
-
Accessors
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-style casts специально позволяет отличать производный класс к защищенному или приватному базовому классу определенным и безопасным способом и передавать в другое направление. Этого следует избегать любой ценой, поскольку он может сделать код зависимым от деталей реализации, но при необходимости вы можете использовать этот метод.
Ответ 4
Это связано с тем, как публичные члены базового класса отображаются из производного класса.
- public → публичные члены базового класса будут общедоступными (обычно по умолчанию)
- protected → публичные члены базового класса будут защищены
- private → публичные члены базового класса будут закрыты
Как видно на рисунке, публичное наследование является традиционным наследованием, которое вы увидите на большинстве языков программирования. Это моделирует отношения "IS-A". Частное наследование, что-то, что AFAIK, свойственное С++, является отношением "ВЫПОЛНЕННЫЕ В УСЛОВИЯХ". То есть вы хотите использовать общедоступный интерфейс в производном классе, но не хотите, чтобы пользователь производного класса имел доступ к этому интерфейсу. Многие утверждают, что в этом случае вы должны агрегировать базовый класс, то есть вместо базового класса в качестве частной базы, сделать в члене производного, чтобы повторно использовать функциональность базового класса.
Ответ 5
Эти три ключевых слова также используются в совершенно другом контексте, чтобы указать модель наследования видимости.
В этой таблице собраны все возможные комбинации объявления компонента и модели наследования, представляющие результирующий доступ к компонентам, когда подкласс полностью определен.
Приведенная выше таблица интерпретируется следующим образом (взгляните на первую строку):
если компонент объявлен как открытый, а его класс наследуется как открытый, доступ к нему является общедоступным.
Пример:
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
Ответ 6
Member in base class : Private Protected Public
Тип наследования: Объект, унаследованный как:
Private : Inaccessible Private Private
Protected : Inaccessible Protected Protected
Public : Inaccessible Protected Public
Ответ 7
1) Публичное наследование:
а. Частные члены базового класса недоступны в классе Derived.
б. Защищенные члены базового класса остаются защищенными в классе Derived.
с. Публичные члены базового класса остаются общедоступными в классе Derived.
Таким образом, другие классы могут использовать публичные элементы базового класса через объект класса Derived.
2) Защищенное наследование:
а. Частные члены базового класса недоступны в классе Derived.
б. Защищенные члены базового класса остаются защищенными в классе Derived.
с. Публичные члены базового класса тоже становятся защищенными членами класса Derived.
Таким образом, другие классы не могут использовать публичные элементы базового класса через Derived class object; но они доступны для подкласса Derived.
3) Частное наследование:
а. Частные члены базового класса недоступны в классе Derived.
б. Защищенные и публичные члены базового класса становятся частными членами класса Derived.
Таким образом, никакие члены базового класса не могут получить доступ к другим классам через объект класса Derived, поскольку они являются частными в классе Derived. Таким образом, даже подкласс Derived класс не может получить к ним доступ.
Ответ 8
Публичное наследование моделирует отношение IS-A. С помощью
class B {};
class D : public B {};
каждый D
является a B
.
Частное наследование моделирует отношения IS-IMPLEMENTED-USING (или что-то другое). С помощью
class B {};
class D : private B {};
a D
не является B
, но каждый D
использует его B
в своей реализации. Частное наследование всегда можно устранить, используя вместо этого сдерживание:
class B {};
class D {
private:
B b_;
};
Этот D
тоже можно реализовать с помощью B
, в этом случае используя его b_
. Сдерживание является менее жесткой связью между типами, чем наследование, поэтому в целом это должно быть предпочтительным. Иногда использование сдерживания вместо частного наследования не так удобно, как частное наследование. Часто это хромое оправдание ленивости.
Я не думаю, что кто-нибудь знает, какие protected
модели наследования. По крайней мере, я пока не вижу убедительного объяснения.
Ответ 9
Если вы наследуете публично из другого класса, все знают, что вы наследуете, и вы можете использовать полиморфно любым путем указателя базового класса.
Если вы наследуете защищенно, только ваши классы-дети смогут использовать вас полиморфно.
Если вы наследуете конфиденциально, то только вы сможете выполнять методы родительского класса.
Что в основном символизирует знание остальных классов о ваших отношениях с вашим родительским классом
Ответ 10
Доступ к защищенным данным может осуществляться любыми классами, которые наследуются от вашего класса. Частные члены данных, однако, не могут. Скажем, мы имеем следующее:
class MyClass {
private:
int myPrivateMember; // lol
protected:
int myProtectedMember;
};
От вашего расширения до этого класса ссылка this.myPrivateMember
не будет работать. Однако this.myProtectedMember
будет. Значение все еще инкапсулировано, поэтому, если у нас есть экземпляр этого класса под названием myObj
, то myObj.myProtectedMember
не будет работать, поэтому он похож по функции на частный элемент данных.
Ответ 11
Резюме:
- Закрыто: никто не видит его, кроме класса
- Защищено: частные + производные классы могут видеть его
- Публикация: мир может видеть это.
При наследовании вы можете (на некоторых языках) изменять тип защиты элемента данных в определенном направлении, например. от защищенных до общественных.
Ответ 12
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... Я думаю, что столик стоит тысячи слов:)
Ответ 13
Частный:
Частным членам базового класса могут быть доступны только члены этого базового класса.
Public:
К открытым членам базового класса могут обращаться члены этого базового класса, члены его производного класса, а также члены, которые находятся за пределами базового класса и производного класса.
Защищено:
К защищенным членам базового класса могут обращаться члены базового класса, а также члены его производного класса.
Короче:
закрытый: базовый
защищенный: base + производный
общедоступный: base + производный + любой другой член
Ответ 14
Я нашел легкий ответ и поэтому подумал о том, чтобы разместить его для моей будущей справки.
Из ссылок 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 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
}
Ответ 15
Это, по сути, защита доступа публичных и защищенных членов базового класса в производном классе. При наличии общего наследования производный класс может видеть общедоступные и защищенные члены базы. При частном наследовании он не может. С защищенным производным классом и любыми полученными из него классами можно их увидеть.
Ответ 16
Смотрите эти коды, чтобы понять особенности С++ о наследовании... Я положил результат в конце... Надеюсь, что это поможет.
#include <iostream>
using namespace std;
class A {
private:
void pri();
A(int a);
protected:
virtual void pro() {}
public:
void pub1() { cout<<"A.pub1()\n"; }
virtual void pub2() { cout<<"A.pub2()\n"; }
virtual void pub3() { cout<<"A.pub3()\n"; }
virtual void pub4() { cout<<"A.pub4()\n"; }
virtual void pub5() { cout<<"A.pub5()\n"; }
virtual void pub6() { cout<<"A.pub6()\n"; }
virtual void pub7() { cout<<"A.pub7()\n"; }
virtual void pub8() { cout<<"A.pub8()\n"; }
void pub9() { cout<<"A.pub9()\n"; }
virtual void pub10() { cout<<"A.pub10()\n"; }
void pub11() { cout<<"A.pub11()\n"; }
explicit A() {}
virtual ~A() {}
};
class B : public A {
private:
void pri() { cout<<"B.pri()\n"; }
protected:
virtual void pub4() { cout<<"B.pub4()\n"; }
void pub6() { cout<<"B.pub6()\n"; }
public:
void pro() { cout<<"B.pro() "; B::pri(); }
void pub1() { cout<<"B.pub1()\n"; }
void pub2() { cout<<"B.pub2()\n"; }
void pub5() { cout<<"B.pub5()\n"; }
virtual void pub7() { cout<<"B.pub7()\n"; }
virtual void pub8() { cout<<"B.pub8()\n"; }
virtual void pub9() { cout<<"B.pub9()\n"; }
void pub10() { cout<<"B.pub10()\n"; }
void pub11() { cout<<"B.pub11()\n"; }
explicit B() {}
};
class C : protected B {
public:
void pub4_() { cout<<"C.pub4_() "; B::pub4(); }
virtual void pub5() { cout<<"C.pub5()\n"; }
};
class D : private B {
public:
void pub4_() { cout<<"D.pub4_() "; B::pub4(); }
};
class E : public B {
public:
virtual void pub4() { cout<<"E.pub4()\n"; }
virtual void pub7() { cout<<"E.pub7()\n"; }
virtual void pub8() { cout<<"E.pub8()\n"; }
virtual void pub9() { cout<<"E.pub9()\n"; }
virtual void pub10() { cout<<"E.pub10()\n"; }
virtual void pub11() { cout<<"E.pub11()\n"; }
};
void testClasses() {
A* ap=new B();
ap->pub1(); // == A::pub1() //important
// (new B()).pub1() can't override non-virtual A::pub1() for an A* pointer.
ap->pub2(); // == B::pub2() //important
// (new B()).pub1() can override virtual A::pub1() for an A* pointer.
B b;
b.A::pub1();
b.pro();
B* bp=new B;
bp->pub3();
C c;
//c.pub3(); //error
//c.pub4(); //error
c.pub4_();
c.pub5();
D d;
//d.pub3(); //error
//d.pub4(); //error
d.pub4_();
E e;
//e.pub4(); //error
delete ap;
ap = new E();
ap->pub4();
ap->pub5();
ap->pub6();
ap->pub7();
delete bp;
bp = new E();
e.pub8();
e.A::pub8();
e.B::A::pub8();
e.B::pub8();
ap->pub8();
bp->pub8();
e.pub9();
e.A::pub9();
e.B::A::pub9();
e.B::pub9();
ap->pub9(); // important
bp->pub9();
e.pub10();
e.A::pub10();
e.B::A::pub10();
e.B::pub10();
ap->pub10(); // important
bp->pub10(); // very important... eventhough B::pub10() is non-virtual,
// bp->pub10() != b.pub10();
e.pub11();
e.A::pub11();
e.B::A::pub11();
e.B::pub11();
ap->pub11();
bp->pub11();
delete ap;
delete bp;
return;
}
int main() {
testClasses();
return 0;
}
/////////////////////////////////////////
........
Result :
........
A.pub1()
B.pub2()
A.pub1()
B.pro() B.pri()
A.pub3()
C.pub4_() B.pub4()
C.pub5()
D.pub4_() B.pub4()
E.pub4()
B.pub5()
B.pub6()
E.pub7()
E.pub8()
A.pub8()
A.pub8()
B.pub8()
E.pub8()
E.pub8()
E.pub9()
A.pub9()
A.pub9()
B.pub9()
A.pub9()
E.pub9()
E.pub10()
A.pub10()
A.pub10()
B.pub10()
E.pub10()
E.pub10()
E.pub11()
A.pub11()
A.pub11()
B.pub11()
A.pub11()
B.pub11()