Следует ли мне избегать делать приватные переменные общедоступными для удобства? - PullRequest
0 голосов
/ 30 октября 2018

У меня есть два объекта, A и B. Сейчас B хранит A как локальную переменную класса.

class B
{
    A myA;
} 

Теперь у B есть куча методов, которые используют свой внутренний myA для выполнения каких-то задач, и я могу использовать эти методы, поскольку они общедоступны.

Но иногда мне нужно использовать сам myA. Так что я сделал это, чтобы сделать это публичным, и тогда я мог написать myB.myA.someMethodFromA().

Это нормально или это плохой стиль? Я имею в виду, я знаю, что мог бы просто предоставить косвенные средства доступа к myA через методы в классе B, но это кажется ненужным, когда я могу просто получить прямой доступ к myA.

Например, если myA имеет метод doStuffviaA, я бы лучше сказал myB.myA.doStuffViaA(), чем сначала нужно написать метод в B, который говорит

void doStuffViaB() { myA.doStuffViaB() }

Но, конечно, если сделать myA публичным, это значит, что его можно изменить, не B зная об этом. ЧТО ДЕЛАТЬ?

Ответы [ 3 ]

0 голосов
/ 30 октября 2018

ЧТО ДЕЛАТЬ?

Это зависит и фактически зависит от конкретного сценария. Как правило, я бы посоветовал вам

  • использовать общедоступные элементы данных только в простых, неинвариантных struct с ( C2 )
  • используйте class, как только у вас есть некоторый инвариант, сделайте элементы данных private ( C2 , C8 )
  • по возможности избегайте добытчиков.

Если последнее невозможно (например, из-за «конструктивных ограничений» или жгучего стремления к «удобству»), вы можете предоставить геттер, как указано в @ ответ Вирсавии . Кроме того, вы можете передать указатель на функцию-член A или функцию, принимающую параметр A&, на шаблон функции-члена B со связанным параметром функции, например,

#include <functional>

class B {
   public:
      template <class MemberFct, class ...Args>
      decltype(auto) invokeOnA(MemberFct fct, Args&&... args)
      {
         return std::invoke(fct, a, std::forward<Args>(args)...);
      }

   private:
      A a;
};

Обратите внимание, что для этого требуется C ++ 17. Учитывая функцию-член A::doStuff(int), этот шаблон может быть создан и вызван с помощью

B b;

b.invokeOnA(&A::doStuff, 42);
b.invokeOnA([](A& a){ a.doStuff(42); });

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

0 голосов
/ 30 октября 2018

Я думаю, вы уже достигли критической точки:

Но, разумеется, опубликование myA означает, что его можно изменить без Зная об этом. ЧТО ДЕЛАТЬ?

Сделать члена публичным или закрытым - это не просто удобство. Спросите себя: существуют ли инварианты, на которые опирается мой класс, которые могут сломаться, если участник публичный?

Только если вы можете определенно ответить на это «нет», вы можете сделать участника публичным. Однако в этом случае вы можете спросить: почему он так или иначе является членом класса?

Рассмотрим простой пример:

struct foo { 
    int a,b,sum;
    foo(int a,int b) : a(a), b(b), sum(a+b) {}
};

Чтобы гарантировать, что sum == a+b всегда выполняется, ни один из членов не должен быть публичным. С другой стороны, рассмотрим std::pair, который является просто структурой данных, поэтому хорошо иметь first и second public.

0 голосов
/ 30 октября 2018

Да, делая его public, обходит инкапсуляцию, и код может закрадываться, что переводит ваш объект в неопределенное состояние.

Вариант дома на полпути будет поставлять

const A& getMyA() const
{
    return myA;
}

с тех пор, по крайней мере, только const функции могут выполняться на элементе myA, если доступ осуществляется с помощью этой функции. Надеюсь, конечно, что doStuffViaA будет const, тогда вы напишите

myB.getMyA().someMethodFromA();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...