为方便起见,我应该避免公开私有字段变量吗?

时间:2018-10-30 11:52:06

标签: c++ design-patterns

我有两个对象A和B。现在,B将A存储为局部类变量。

class B
{
    A myA;
} 

现在,B有很多方法,它们使用其内部的myA做一些事情,并且我可以使用这些方法,因为它们是公共的。

但是有时候,我需要使用myA本身。所以我要做的就是将其公开,然后我可以写myB.myA.someMethodFromA()

这还好吗,还是风格不好?我的意思是,我知道我可以通过B类中的方法提供对myA的间接访问器,但是当我可以直接访问myA时,这似乎是不必要的。

例如,如果myA拥有方法doStuffviaA,我宁愿说myB.myA.doStuffViaA(),而不必先在B中写一个方法说

void doStuffViaB() { myA.doStuffViaB() }

但是,当然,myA公开意味着它可以在B不知道的情况下进行更改。该怎么办?

3 个答案:

答案 0 :(得分:3)

是的,使其成为public可以避免封装,并且代码会不断蔓延,从而使您的对象进入不确定的状态。

半途而废的选择是供应

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

从那时起,如果至少使用const个功能,则只能在myA成员上执行此功能。我当然希望doStuffViaA const,然后您会写

myB.getMyA().someMethodFromA();

答案 1 :(得分:2)

  

该怎么办?

这取决于并且实际上非常取决于特定的方案。通常,我建议您

  • 仅在无变量的structC2)内使用公共数据成员
  • 一旦有了一些不变性,就使用class,使数据成员成为privateC2C8
  • 尽可能避免使用吸气剂。

如果无法使用后者(例如,由于“设计约束”或对“便利”的强烈渴望),则可以提供@Bathsheba's answer中发布的吸气剂。另外,您可以将指向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); });

可以通过另一种间接方式解决该问题,而无需使用getter方法。但是请注意,该方法在质量上与提供一种getter方法非常相似,即拥有精美的功能模板并不能使您摆脱在特定用例中必须打破封装的理由。

答案 2 :(得分:0)

我认为您已经达到了关键点:

  

但是,当然,将myA公开意味着无需更改即可   B知道了。该怎么办?

使成员成为公共或私人成员不只是为了方便。问问自己:如果成员是公开的,我的班级依赖的不变式会否打破?

仅当您可以肯定地以“否”回答时,您才能将成员公开。但是,在这种情况下,您可能会问:为什么仍然是该类的成员?

考虑这个简单的示例:

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

为确保sum == a+b始终有效,所有成员都不应该公开。另一方面,请考虑std::pair,它只是一种数据结构,因此可以公开使用firstsecond