Когда/зачем делать функцию приватной в классе?
Когда мне нужно сделать функцию private
и почему это хорошая идея?
Ответы
Ответ 1
Вы должны сделать функцию private
, когда вам не нужны другие объекты или классы для доступа к этой функции, когда вы будете вызывать ее из класса.
Придерживайтесь принципа наименьших привилегий, разрешайте доступ к переменным/функциям, которые абсолютно необходимы. Все, что не соответствует этим критериям, должно быть private
.
Ответ 2
Я обычно делаю вспомогательные функции private
. Но то, что помощник, кажется, расплывчато. Поэтому позвольте мне привести вам пример. Предположим, что у вас есть следующий класс Sample
; он раскрывает несколько общественных функций, один из них, скажем, DoWork()
. Эта функция принимает один параметр. Но он не предполагает, что параметр всегда будет действительным, поэтому first проверяет правильность параметра, для которого у него много кода в начале функции. Что-то вроде этого:
class Sample
{
public:
void DoWork(SomeClass param)
{
/*
*lots of code related to validation of param
*/
//actual code that operates on the param
//and other member data IF the param is valid
}
};
Поскольку вы написали много кода, связанного с проверкой параметра, он делает функцию громоздкой и трудночитаемой. Поэтому вы решили перенести этот код проверки на функцию say, IsValidParam()
, а затем вы вызываете эту функцию из DoWork()
, передавая ей параметр param
. Что-то вроде этого:
class Sample
{
public:
void DoWork(SomeClass param)
{
if ( IsValidParam(param))
{
//actual code that operates on the param
//and other member data IF the param is valid
}
}
};
Это выглядит чище, не так ли?
Хорошо, вы написали IsValidParam()
где-то в классе, но вопрос, с которым вы сейчас сталкиваетесь, не мог бы вы сделать эту функцию public
? Если эта функция используется только другими вашими функциями, такими как DoWork()
, то создание IsValidParam()
public не имеет смысла. Итак, вы решили сделать эту функцию private
.
class Sample
{
public:
void DoWork(SomeClass param)
{
if ( IsValidParam(param))
{
//actual code that operates on the param
//and other member data IF the param is valid
}
}
private:
bool IsValidParam(SomeClass param)
{
//check the validity of param.
//return true if valid, else false.
}
};
Функции такого рода (IsValidParam) должны быть private
. Я называю эти вспомогательные функции функциями.
Надеемся, что это объяснение поможет вам!
Ответ 3
Одним из основополагающих принципов ООП является инкапсуляция. Здесь функциональность для работы объекта сохраняется внутри этого объекта. Идея состоит в том, что проще использовать код для использования объекта, если ему не нужно знать, как он работает. Как будто вы покупаете микроволновую печь - вам просто нужно знать, как ее использовать, а не как это работает.
Такой же подход следует применять с ООП. Храните все необходимое, чтобы сохранить объект закрытым. Сделайте только то, что необходимо для полного использования публичного объекта.
Ответ 4
Если вы разрабатываете класс - учитывая способ использования клиентского кода, то вы неизбежно получите интерфейс, состоящий из членов public
и, возможно, protected
.
private
члены - это функции и данные, которые поддерживают и разрешают эти публичные/защищенные члены. private
функции должны учитывать и/или модулировать/структурировать код, необходимый членам private
, делая их реализацию менее избыточной и понятной.
В итоге вы создаете член private
, если он не предназначен для прямого использования клиентским кодом и существует только для поддержки членов private
.
Ответ 5
Как вы хотите быть пуристом?:)
Правильный ответ на этот вопрос связан с поддержанием инвариантов. Правильный способ сделать это довольно сложно.
В базовом классе вы определяете общедоступные методы для предоставления целого доступа к классу. Все эти методы должны быть конкретными. Ключевым моментом здесь является то, что публичные инварианты предполагаются удерживать до и после вызова этих функций. Эти функции никогда не должны звонить друг другу, они вызывают только защищенные и частные методы. Эти функции должны быть аксиоматическими: они должны быть достаточно минимальным набором, необходимым для захвата желаемой семантики.
Большинство вычислений, которые могут быть выполнены с использованием этих методов, должны быть глобальными или, по крайней мере, публичными статическими членами.
Вы также предоставляете чистые виртуальные методы, которые являются крючками для реализации деталей в зависимости от представления в производных классах. Виртуальные функции в базе должны быть частными. Обычный совет здесь (публичный) совершенно неверен. Виртуальные функции - это детали реализации. Одно исключение: виртуальный деструктор должен быть общедоступным.
Частные вспомогательные функции также могут быть помещены в базу.
Может быть полезно также иметь защищенные методы в базе: они будут вызывать частные помощники или виртуальные. Как и выше: защищенные методы никогда не должны вызывать защищенные или общедоступные методы. Защищенные функции поддерживают более слабый инвариант, чем открытый, до и после каждого вызова.
Частные функции обычно поддерживают очень слабые инварианты.
Причиной этой строгой иерархии является обеспечение правильного поддержания инвариантов объекта.
Теперь в производном классе вы предоставляете реализацию. В идеале, виртуальные функции здесь были бы невидимыми, что более сильное условие, чем просто личное. Эти виртуальные функции вообще не должны вызываться в производном классе. Разрешенный доступ только осуществляется через защищенные функции базы.
Все методы производных классов, включая деструктор, должны быть частными. Конструкторы должны быть общедоступными, но они не являются методами класса.
Чтобы полностью понять эти правила, вы должны тщательно подумать об инвариантах. Предполагается, что публичные инварианты сохраняются до вызова общедоступного метода и должны удерживаться после его завершения. Поэтому вы не можете вызывать такие функции изнутри класса или любого производного от него класса, поскольку эти функции используются для изменения представления между началом и концом публичной функции и поэтому неизбежно нарушают публичные инварианты: почему они должны не вызывать публичные функции.
Тот же аргумент применяется к защищенным функциям: функции могут вызывать только функции с более слабыми инвариантами.
Виртуальные функции всегда вызываются публикой из общедоступных оберток базового класса, чтобы гарантировать, что последовательность операций, которая нарушает публичные инварианты, никогда не прерывается возвращением общественности со сломанным инвариантом. Набор самих виртуальных объектов представляет собой инвариантную структуру, которую должно иметь любое представление. Делая это, все манипуляции с представлением для выполнения вычислений для публичных клиентов могут быть абстрагированы в базу.
На практике эти правила обычно не соблюдаются, потому что они часто генерируют тривиальные обертки и содержат много дополнительного кода для написания и поддержки. Таким образом, виртуальные функции часто становятся публичными, даже если это полностью и совершенно неправильно в принципе.
Ответ 6
Перед созданием функции или класса мы должны понимать область действия этой функции или класса, будь то глобально или локально.
например: "ConnectionString()".
Каждому соединению с базой данных требуется "ConnectionString()", поэтому его объявленный Public.
Ответ 7
private: используется только этим классом, не используется другими классами и производными классами.
protected: используется этим классом и, возможно, производными классами, но не используется другими классами.
public: используется другим классом, этим классом и производным классом.
Трудно выбирать между частным и защищенным. Поэтому я всегда защищаю функцию, если есть 1% вероятность того, что производные классы могут нуждаться в ней.