Частные и защищенные члены: C ++


277

Может кто - нибудь просветить меня, чтобы разница между privateи protectedчленами в классах?

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

Какая разница и какую мне использовать?

Ответы:


375

Частные члены доступны только в пределах класса, определяющего их.

Защищенные члены доступны в классе, который их определяет, и в классах, которые наследуются от этого класса.

Изменить: оба также доступны друзьям их класса, а в случае защищенных членов - друзьям их производных классов.

Изменить 2: Используйте все, что имеет смысл в контексте вашей проблемы. Вы должны стараться сделать члены закрытыми, когда вы можете уменьшить сцепление и защитить реализацию базового класса, но если это невозможно, используйте защищенные члены. Проверьте C ++ FAQ для лучшего понимания проблемы. Этот вопрос о защищенных переменных также может помочь.


12
Ссылка на C ++ FAQ Lite переехал isocpp.org/wiki/faq/basics-of-inheritance
Авнер

134

Публичные члены класса А доступны для всех и каждого.

Защищенные члены класса A не доступны вне кода A, но доступны из кода любого класса, производного от A.

Закрытые члены класса A не доступны вне кода A или из кода любого класса, полученного из A.

Итак, в конце концов, выбор между защищенным или частным ответит на следующие вопросы: Какое доверие вы готовы оказать программисту производного класса?

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


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

@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 цель состоит в том, чтобы сделать все частным, включая методы, чтобы ограничить ущерб, который создатель производного класса может нанести иерархии. Защищенные методы уже являются потенциальной проблемой. Я не убежден, что усугублять это, используя защищенное государство, - правильный подход.
paercebal

Это может быть, что потребует наличия виртуальных «получателей» в базовом классе для доступа к нему. И хотя у вас могут быть промежуточные классы для разных способов реализации шаблона данных, это не всегда практично. Например, «шаблон», распространенный в языках, в которых нет модификатора «const», хотя в С ++ и не требуется большую часть времени, - это наличие базового класса только для чтения и доступных для записи производных классов. В C ++ это также может быть удобно просто потому, что вам требуется более одного возможного способа загрузки (инициализации) данных.
CashCow

Есть разные способы сделать это. Сделайте ваши классы сериализации друзьями. Поместите все свои данные в структуру с открытым доступом, но у вашего класса есть закрытый член этой переменной .... Защищенные члены и производные классы для загрузки их из любого источника иногда проще.
CashCow

63

Защищенные члены могут быть доступны из производных классов. Частные не могут.

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
};

С точки зрения «лучшей практики», это зависит. Если есть даже слабая вероятность того, что кто-то захочет получить новый класс из вашего существующего и ему нужен доступ к внутренним членам, сделайте их Защищенными, а не Приватными. Если они частные, ваш класс может стать трудным для наследования.


3
Я позволю себе не согласиться: если есть слабая вероятность того, что никакой подкласс не будет нуждаться в этом, сделайте это частным. Если вы не собираетесь , чтобы ваш класс подклассов, использовать шаблон метода шаблона.
xtofl

23

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


9

Все зависит от того, что вы хотите сделать, и что вы хотите, чтобы производные классы могли видеть.

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
    }
}

6

Атрибуты и методы, помеченные как protected- в отличие от частных - все еще видимы в подклассах.

Если вы не хотите использовать или предоставлять возможность переопределить метод в возможных подклассах, я бы сделал их private.


2
Производный класс может переопределять частные виртуальные функции своей базы
Джеймс Хопкин

6

Обязательно посмотрите вопрос о переменных защищенных членов . По умолчанию рекомендуется использовать private (как это classделают C ++ ), чтобы уменьшить связь. Защищенные переменные-члены чаще всего плохая идея, защищенные функции-члены могут использоваться, например, для шаблона Template Method.


Забавно, я отредактировал это в своем посте до того, как увидел ваш. Проголосовал за то, что пернатые птицы натыкаются на одну и ту же ссылку :)
Firas Assaad

4

Защищенные члены могут быть доступны только потомкам класса и по коду в том же модуле. Доступ к закрытым членам возможен только по классу, в котором они объявлены, и по коду в том же модуле.

Конечно функции друзей выбрасывают это в окно, ну да ладно.


4

закрытые члены доступны только внутри класса, защищенные члены доступны в классе и производных классах. Это особенность наследования в ОО языках.

Вы можете иметь частное, защищенное и открытое наследование в C ++, которое будет определять, какие производные классы могут получить доступ в иерархии наследования. Например, C # имеет публичное наследование.


3

личное = доступно только для корабля (базовый класс) (т.е. только мой родитель может войти в спальню моего родителя)

защищен = доступен для материнства (базовый класс) и ее дочерей (т.е. только мой родитель может войти в спальню моего родителя, но разрешил сыну / дочери пройти в спальню родителей)

public = доступно для материнства (базовый класс), дочери и всех остальных (т.е. только мой родитель может войти в спальню моих родителей, но это домашняя вечеринка - mi casa su casa)


2

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


Вы всегда можете использовать встроенную функцию, реализованную в объявлении класса. Компилятор оптимизирует это (и это было бы хорошим способом обеспечить доступ только для чтения к закрытой переменной-члену, например).
Пол Сандерс

2

privateявляется предпочтительным для данных участника. Члены в классах C ++ являются privateпо умолчанию.

publicпредпочтительнее для функций-членов, хотя это вопрос мнения. По крайней мере, некоторые методы должны быть доступны. publicдоступно для всех. Это наиболее гибкий и наименее безопасный вариант. Любой может использовать их, и любой может злоупотреблять ими.

privateне доступен вообще. Никто не может использовать их вне класса, и никто не может злоупотреблять ими. Даже в производных классах.

protectedэто компромисс, потому что он может быть использован в производных классах. Когда вы выходите из класса, вы хорошо понимаете базовый класс и стараетесь не злоупотреблять этими членами.

MFC - оболочка C ++ для Windows API, она предпочитает publicи protected. Классы , создаваемые Visual Studio Wizard имеют уродливую смесь protected, publicи privateчленов. Но есть некоторая логика для самих классов MFC.

Участники, такие как SetWindowText, publicпотому что вам часто нужно получить доступ к этим членам.

Члены, такие как OnLButtonDown, обрабатывают уведомления, полученные окном. Они не должны быть доступны, поэтому они есть protected. Вы по-прежнему можете обращаться к ним в производном классе, чтобы переопределить эти функции.

Некоторые члены должны делать потоки и циклы сообщений, к ним нельзя обращаться или переопределять, поэтому они объявлены как private

В структурах C ++ члены publicпо умолчанию. Структуры обычно используются только для данных, а не для методов, поэтому publicобъявление считается безопасным.


1
Вы пишете "Члены в классах C ++ защищены по умолчанию". Согласно стандарту, они являются либо частными, либо открытыми по умолчанию, в зависимости от того, какое ключевое слово было использовано в определении (14p3). Microsoft отклоняется от стандарта здесь?
Александр Клауэр

@AlexanderKlauer Я ошибся, privateпо умолчанию в Visual Studio. Это также privateпо умолчанию в gcc, publicпо умолчанию никогда . Если я не ошибаюсь снова. Я не могу найти стандарт, на который вы ссылаетесь.
Бармак Шемирани

Извините, я должен был быть более конкретным. Я имел в виду стандарт C ++ 17. Стандарт C ++ 11 имеет ту же формулировку в 11p3. Не могли бы вы обновить свой ответ? Спасибо!
Александр Клауэр

1

Доступ к закрытому члену возможен только в том же классе, где он объявлен, а в качестве защищенного члена - в классе, где он объявлен, вместе с классами, унаследованными им


1
  • Частный : это спецификатор доступа. По умолчанию переменные экземпляра (члена) или методы класса в c ++ / java являются закрытыми. Во время наследования код и данные всегда наследуются, но не доступны вне класса. Мы можем объявить наши элементы данных как частные, чтобы никто не мог вносить прямые изменения в наши переменные-члены, и мы можем предоставить общедоступные методы получения и установки для изменения наших частных членов. И эта концепция всегда применяется в бизнес-правилах.

  • Защищено : это также спецификатор доступа. В C ++ защищенные члены доступны внутри класса и унаследованному классу, но не за его пределами. В Java защищенные члены доступны внутри класса, унаследованному классу, а также всем классам в одном пакете.


0

Доступ к защищенному нестатическому члену базового класса могут получить члены и друзья любых классов, производных от этого базового класса, с помощью одного из следующих:

  • Указатель на прямо или косвенно производный класс
  • Ссылка на прямо или косвенно производный класс
  • Объект прямо или косвенно производного класса

0

Личное: доступно для функций-членов класса и функции друга или класса друга. Для класса C ++ это спецификатор доступа по умолчанию.

Защищено: Доступно для функций-членов класса, функции-друга или класса-друга и производных классов.

  • Вы можете хранить переменную или функцию члена класса (даже typedefs или внутренние классы) как приватные или защищенные в соответствии с вашими требованиями.
  • Большую часть времени вы оставляете член класса закрытым и добавляете функции get / set для инкапсуляции. Это помогает в обслуживании кода.
  • Обычно закрытая функция используется, когда вы хотите сохранить свои открытые функции модульными или исключить повторяющийся код вместо записи всего кода в одну функцию. Это помогает в обслуживании кода.

Обратитесь по этой ссылке для более подробной информации.


-2

Модификаторы закрытого и защищенного доступа - это одно и то же только то, что защищенные члены базового класса могут быть доступны вне области базового класса в дочернем (производном) классе. Это также относится и к наследованию. Но с модификатором private доступ к членам базового класса возможен только в области видимости или коде базового класса, и только его дружественные функции '' ''


5
Какую ценность ваш ответ добавляет к другим ответам?
Герман Деппс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.