【问题标题】:Only allow access to an object's members, not the object itself只允许访问对象的成员,而不是对象本身
【发布时间】:2019-06-15 12:17:00
【问题描述】:

给定以下类:

class Foo
{
public:

    //...

private:

    Bar mBar;
};

是否可以公开mBar 成员,使其成员可以被访问,而不是mBar 对象本身?

原因是用户应该能够访问mBar 的所有成员,但他们不能将另一个Bar 实例分配给mBarBar 有很多成员,为他们编写 getter/setter 和转发函数会很麻烦。但是,如果mBar 公开,则可以做aFoo.mBar = Bar(/*...*/);,这是唯一不应该被允许的事情。 删除Bar 的赋值运算符不是一种选择。

【问题讨论】:

  • 是否从Bar 继承一个选项(在您的特定设计计划中)?
  • 你想让mBar的成员可以被外部用户修改吗?
  • 提供getter const Bar& getBar() const { return mBar;}?
  • aFoo.mBar = Bar(/*...*/); ... 是唯一不应该被允许的事情 - 但是应该允许为 mBar 成员分配新值?
  • 设计合理吗?您能否将理论上的 Foos 和 Bars 替换为有助于可视化您要完成的工作的名称?一个想法:将Bar 包装在一个不可复制/可移动的容器中,并像@Jarod42 建议的那样公开它,只有非常量。

标签: c++ wrapper encapsulation forwarding


【解决方案1】:

如果您只想防止错误而不是 Machiavelli,operator-> 可能会有所帮助(您可能需要一个包装器而不是直接将其放入 foo):

class Foo
{
public:
    //...
    const Bar* operator ->() const { return &mBar; }
    Bar* operator ->() { return &mBar; }
private:
    Bar mBar;
};

所以

Foo foo;

foo->bar_member;
foo.foo_member;

// Machiavelli
*foo.operator->() = Bar();

【讨论】:

  • 恕我直言,封装的主要原因是防止错误,而不是恶意,所以这看起来很有希望。
【解决方案2】:

我可能会重新考虑您的设计,但这是一种使用中间 get 方法的可能间接方式:

struct Bar {
    int intAttr;
};

class Foo {
    Bar mBar;

public:

    template <class U>
    U& get(U Bar::* p) {
        return mBar.*p;
    }
};

这样,您可以使用以下方式访问mBar 的任何公共成员:

Foo foo;
foo.get(&Bar::intAttr);      // get
foo.get(&Bar::intAttr) = 0;  // set

【讨论】:

  • 甚至可以使用可变参数,std::invoke 允许成员方法和成员非方法
  • @Jarod42 是的,但是你必须小心,正如你所说的那样,Machiavelli,因为你可以使用operator= 来设置mBar 本身; )
  • 确实如此。它并不是真正的黑客(而我的是 IMO)。一个简单的static_assert 可能很容易解决它。
  • @Holt "Rethink the design" - 是不是闻所未闻Bar自己的接口被充分封装,可以直接暴露,但Foo必须保护的唯一不变的是on Bar 是如何构造的? (Bar 是一个成熟的类顺便说一句,不是一个简单的结构)。
  • @Unimportant 我并不是说这是不可能的,但这充其量看起来很可疑。首先是你有一个类Bar,它似乎有不同的行为,具体取决于你如何构造它......如果Bar 是不可变的,那么我会完全理解你可能有不同的构造函数来设置一个Bar 实例处于不同的状态,然后您只想为Foo 允许这些构造之一,但在这种情况下,通过const&amp; 访问mBar 就足够了。这里似乎不是这样,所以Bar 的设计在我看来并不合理。
猜你喜欢
  • 1970-01-01
  • 2013-08-31
  • 1970-01-01
  • 1970-01-01
  • 2010-12-05
  • 2011-04-07
  • 2013-10-04
  • 2016-09-05
  • 1970-01-01
相关资源
最近更新 更多