Частные и защищенные члены: 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.