В чем разница между членами private и protected в классах C++?
Из соглашений о передовой практике я понимаю, что переменные и функции, которые не вызываются вне класса, должны быть сделаны как private, но, глядя на мой проект MFC, кажется, что MFC отдает предпочтение protected.
В чем разница и что мне использовать?





Закрытые члены доступны только в пределах определяющего их класса.
Защищенные члены доступны в классе, который их определяет, и в классах, наследующих от этого класса.
Обновлено: оба также доступны друзьям своего класса, а в случае защищенных членов - друзьям их производных классов.
Изменить 2: используйте все, что имеет смысл в контексте вашей проблемы. Вы должны стараться сделать члены закрытыми, когда это возможно, чтобы уменьшить взаимосвязь и защитить реализацию базового класса, но если это невозможно, используйте защищенные члены. Проверьте C++ FAQ, чтобы лучше понять проблему. Этот вопрос о защищенных переменных также может помочь.
Атрибуты и методы, помеченные как protected, - в отличие от частных - все еще видны в подклассах.
Если вы не хотите использовать или предоставлять возможность переопределить метод в возможных подклассах, я бы сделал их private.
Производный класс может переопределять частные виртуальные функции своей базы
Доступ к защищенным членам могут получить только потомки класса и код в том же модуле. Доступ к закрытым членам может осуществляться только классом, в котором они объявлены, и кодом в том же модуле.
Конечно, дружественные функции выкидывают это в окно, ну да ладно.
частные члены доступны только изнутри класса, защищенные члены доступны в классе и производных классах. Это особенность наследования в объектно-ориентированных языках.
У вас может быть частное, защищенное и открытое наследование в C++, которое будет определять, к каким производным классам можно получить доступ в иерархии наследования. Например, C# имеет только публичное наследование.
Доступ к защищенным членам можно получить из производных классов. Частные не могут.
class Base {
private:
int MyPrivateInt;
protected:
int MyProtectedInt;
public:
int MyPublicInt;
};
class Derived : Base
{
public:
int foo1() { return MyPrivateInt;} // Won't compile!
int foo2() { return MyProtectedInt;} // OK
int foo3() { return MyPublicInt;} // OK
};
class Unrelated
{
private:
Base B;
public:
int foo1() { return B.MyPrivateInt;} // Won't compile!
int foo2() { return B.MyProtectedInt;} // Won't compile
int foo3() { return B.MyPublicInt;} // OK
};
С точки зрения «лучшей практики» это зависит от обстоятельств. Если есть хотя бы небольшая вероятность того, что кто-то может захотеть унаследовать новый класс от вашего существующего и ему потребуется доступ к внутренним членам, сделайте их защищенными, а не закрытыми. Если они частные, ваш класс может стать трудным для наследования.
Я прошу не согласиться: если есть слабая вероятность того, что подклассу нет он понадобится, сделайте его закрытым. Если вы не намереваться, чтобы ваш класс был подклассом, используйте шаблон метода шаблона.
Причина, по которой MFC предпочитает защищенный, заключается в том, что это фреймворк. Вероятно, вы захотите создать подклассы классов MFC, и в этом случае необходим защищенный интерфейс для доступа к методам, которые не видны для общего использования класса.
Члены класса A Общественные доступны всем и каждому.
Члены Защищено класса A недоступны вне кода A, но доступны из кода любого класса, производного от A.
Члены Частный класса A недоступны вне кода A или из кода любого класса, производного от A.
Итак, в конце концов, выбор между защищенным или частным отвечает на следующие вопросы: Какое доверие вы готовы оказать программисту производного класса?
По умолчанию, предполагается, что производному классу нельзя доверять, и сделайте своих членов приватными. Если у вас есть веская причина предоставить свободный доступ к внутренним компонентам материнского класса его производным классам, вы можете сделать их защищенными.
Производный класс должен быть типом вашего класса, а защищенные данные базового класса являются частью данных производного класса. Ожидается, что средство записи производного класса обработает эти данные должным образом, в противном случае это ошибка. Однако частные данные в базовом классе не контролируются автором производного класса.
@CashCow the protected data of the base class is part of the data of the derived class. Действительно. Не лучше ли, чтобы автор производного класса объявлял эти данные в своем классе, а не в моем? ... :-) ... The writer of the derived class is expected to handle this data properly or it is a bug. В шаблоне NVI цель состоит в том, чтобы сделать все приватным, включая методы, чтобы ограничить ущерб, который средство записи производного класса может нанести иерархии. Защищенные методы уже представляют собой потенциальную проблему. Я не уверен, что усугублять ситуацию за счет использования защищенного государства - это правильный подход.
Это может быть так, что вам потребуются виртуальные «геттеры» в базовом классе для доступа к нему. И хотя у вас могут быть промежуточные классы для различных способов реализации шаблона данных, это не всегда практично. Например, «шаблон», распространенный в языках, не имеющих модификатора «const», хотя и не обязательный большую часть времени в C++, должен иметь базовый класс только для чтения и производные классы с возможностью записи. В C++ это также может быть удобно просто потому, что вам нужно более одного способа загрузки (инициализации) данных.
Это можно сделать разными способами. Сделайте свои классы сериализации друзьями. Поместите все свои данные в структуру с общедоступным доступом, но у вашего класса есть частный член этой переменной .... Защищенные члены и производные классы, чтобы загрузить их из любого источника, иногда проще.
Все зависит от того, что вы хотите сделать и что вы хотите, чтобы производные классы могли видеть.
class A
{
private:
int _privInt = 0;
int privFunc(){return 0;}
virtual int privVirtFunc(){return 0;}
protected:
int _protInt = 0;
int protFunc(){return 0;}
public:
int _publInt = 0;
int publFunc()
{
return privVirtFunc();
}
};
class B : public A
{
private:
virtual int privVirtFunc(){return 1;}
public:
void func()
{
_privInt = 1; // wont work
_protInt = 1; // will work
_publInt = 1; // will work
privFunc(); // wont work
privVirtFunc(); // wont work
protFunc(); // will work
publFunc(); // will return 1 since it's overridden in this class
}
}
Обязательно взгляните на вопрос Защищенные переменные-члены. Рекомендуется использовать private по умолчанию (как это делают C++ classses), чтобы уменьшить взаимосвязь. Защищенные переменные-члены всегда являются плохой идеей, защищенные функции-члены могут использоваться, например, для шаблон "Шаблонный метод".
Забавно, я отредактировал это в своем посте до того, как увидел ваш. Проголосовали, потому что пернатые птицы натыкаются на ту же ссылку :)
Поскольку для выборки и обновления защищенных членов в производном классе не требуется общедоступная функция-член, это увеличивает эффективность кода и сокращает объем кода, который нам нужно написать. Однако предполагается, что программист производного класса знает, что он делает.
Вы всегда можете использовать встроенную функцию, реализованную в объявлении класса. Компилятор оптимизирует это (и это было бы хорошим способом обеспечить доступ только для чтения к частной переменной-члену, например).
Доступ к закрытому члену можно получить только в том же классе, где он объявлен, где как защищенный член может быть доступен в классе, где он объявлен вместе с классами, которые он унаследовал.
Доступ к защищенному нестатическому члену базового класса могут получить члены и друзья любых классов, производных от этого базового класса, с помощью одного из следующих способов:
Частный: это спецификатор доступа. По умолчанию переменные экземпляра (члена) или методы класса в C++ / java являются частными. Во время наследования код и данные всегда наследуются, но недоступны за пределами класса. Мы можем объявить наши элементы данных как частные, чтобы никто не мог напрямую изменять наши переменные-члены, и мы можем предоставить общедоступные методы получения и установки для изменения наших частных членов. И это понятие всегда применяется в бизнес-правиле.
Защищено: это также спецификатор доступа. В C++ защищенные члены доступны внутри класса и для унаследованного класса, но не за его пределами. В Java защищенные члены доступны внутри класса для унаследованного класса, а также для всех классов в одном пакете.
модификаторы доступа private и protected - это одно и то же, только то, что к защищенным членам базового класса можно получить доступ вне области действия базового класса в дочернем (производном) классе. То же самое относится и к наследованию. Но с модификатором private доступ к членам базового класса можно получить только в области видимости или коде базового класса и только его дружественных функций '' ''
Какое значение ваш ответ имеет по сравнению с другими ответами?
частный = доступно только для материнского корабля (базовый класс) (т.е. только мой родитель может войти в спальню моих родителей)
защищенный = доступно для материнского корабля (базовый класс) и ее дочерей (т.е. только мой родитель может войти в родительскую спальню, но разрешил сыну / дочери войти в родительскую спальню)
общественный = доступно для материнского корабля (базовый класс), дочери и всех остальных (т.е. только мой родитель может войти в спальню моих родителей, но это домашняя вечеринка - mi casa su casa)
private предпочтительнее для членских данных. Членами в классах C++ по умолчанию являются private.
public предпочтительнее для функций-членов, хотя это вопрос мнения. По крайней мере, какие-то методы должны быть доступны. public доступен всем. Это наиболее гибкий вариант и наименее безопасный. Кто угодно может их использовать, и кто угодно может использовать их не по назначению.
private вообще недоступен. Никто не может использовать их вне класса, и никто не может ими злоупотреблять. Даже в производных классах.
protected - это компромисс, поскольку его можно использовать в производных классах. Когда вы производите от класса, вы хорошо понимаете базовый класс и стараетесь не использовать эти члены неправильно.
MFC - это оболочка C++ для Windows API, она предпочитает public и protected. Классы, созданные мастером Visual Studio, содержат ужасное сочетание членов protected, public и private. Но в самих классах MFC есть некоторая логика.
Такие члены, как SetWindowText, являются public, потому что вам часто требуется доступ к этим членам.
Такие члены, как OnLButtonDown, обрабатывают уведомления, полученные окном. К ним нельзя обращаться, поэтому они protected. Вы по-прежнему можете получить к ним доступ в производном классе, чтобы переопределить эти функции.
Некоторые участники должны выполнять потоки и циклы сообщений, к ним нельзя обращаться или переопределять, поэтому они объявлены как private.
В структурах C++ членами по умолчанию являются public. Структуры обычно используются только для данных, а не для методов, поэтому объявление public считается безопасным.
Вы пишете «Члены в классах C++ защищены по умолчанию». Согласно стандарту, по умолчанию они либо частные, либо общедоступные, в зависимости от того, какое ключевое слово было использовано в определении (14p3). Microsoft здесь отклоняется от стандарта?
@AlexanderKlauer Я ошибался, это private по умолчанию в Visual Studio. По умолчанию это private и в gcc, но никогда не public. Если я снова не ошибаюсь. Я не могу найти стандарт, о котором вы говорите.
Извините, мне следовало быть более конкретным. Я имел в виду стандарт C++ 17. В стандарте C++ 11 такая же формулировка в 11p3. Не могли бы вы обновить свой ответ? Спасибо!
Частный : Доступен для функций-членов класса и дружественной функции или дружественного класса. Для класса C++ это спецификатор доступа по умолчанию.
Защищено: Доступен для функций-членов класса, дружественной функции или дружественного класса и производных классов.
Обратитесь по этой ссылке для более подробной информации.
Ссылка на C++ FAQ Lite перенесена на isocpp.org/wiki/faq/basics-of-inheritance