【发布时间】:2014-06-16 22:55:19
【问题描述】:
让Foo 类有一些 const 和 non-const 方法
struct Foo
{
Foo ();
~Foo();
void noSideEffect() const;
void withSideEffect();
};
我还有一个Bar 类,需要以某种方式引用Foo。更准确地说,也许对于这个问题来说太精确了,Bar 实现了运算符|| 和&& 用于联合和交集,所以两个Bar 实例需要知道他们正在处理Foo 的同一个实例。
我找到的最简单的解决方案是使用指向 Foo 对象的指针:
struct Bar
{
Foo * p_foo;
Bar (Foo& foo)
: p_foo(&foo) {};
}
现在两个 bar 实例可以一起玩,看看它们是否都处理同一个 Foo。我几乎很高兴。
但现在我想有时将 Bar 与 const Foo 实例一起使用。好吧,这可能很简单,我只需要创建一个const Bar 实例,对吗?我们去:
const Bar createBarFromConstFoo(const Foo& foo)
{
Foo* newfoo = const_cast<Foo*>(&foo);
const Bar newbar (*newfoo);
return newbar;
}
现在噩梦开始了(见Why doesn't C++ enforce const on pointer data?)。我想我理解为什么(标准是这样说的),我的主要问题是如何最好地应对它。
除了这个标准的小东西,createBarFomConstFoo 几乎可以满足我的要求,因为它返回一个const Bar。
有没有办法防止const Bar 用我的(最初)const Foo 做讨厌的事情(即只调用 Foo 的 const 方法)同时允许非常量 Bar 做所有事情?
也许没有办法做到这一点,这是一个对象设计问题,但我没有看到一个简单的替代方案。
编辑:对于downvoters,你能解释一下原因吗,我也许可以从你的言论中取得进展......
编辑 2:也许混淆 Foo 和 Bar 的真实类是个坏主意,我只是想简化一些事情。
所以Foo 实际上是一个分子(实际上是一种蛋白质),其中包含原子(许多用于蛋白质)。能够选择一些原子是创建 Bar 的原因,它是 SelectionOfAtoms。
有时选择所有的氢原子和氧原子是很方便的,因此 Bar 实现了并集和交集。我希望能够提取这些原子,以便 SelectionOfAtoms 从选定的原子中实现 createNewMolecule() 方法。因此,它需要一种引用原始分子的方法(也许在这里可以使用某种副本,但可能不适用于下面的其他要求)。
但我最近觉得有必要修改选择的原子,同时保持其他原子不变。通过 SelectionOfAtoms (Bar) 进行操作很方便:它已经知道在哪里可以找到原子(使用指针)和这些原子的索引(内部实现细节),所以更改原子所需的一切几乎都已经在这里了,除了我可以要么仅在 Molecule(非 const)上使用 Selection,要么在 const Molecule 上工作而忘记修改它们,或者进入 const_cast 恐怖。
我确信这是一个非常糟糕的设计,但它已经存在,它肯定可以改进很多。
【问题讨论】:
-
如果我是正确的,使用
Foo * const ptrBar 永远无法修改 Foo。我希望非 constBar对其Foo执行任何操作,同时防止const Bar调用修改ptr指向的数据的方法。 -
你可以做类似
const_iterator/iterator的事情。 (也许让Bar一个模板类使用一些policy)。 -
噩梦从你输入
const_cast的那一刻开始 -
Bar实例是否需要修改Foo对象的内容?还是他们只关心对象的身份(地址)? -
我知道在屋内开枪是个糟糕的决定,但我差点把沙发上的灯关掉……。如果您能回答上述评论中的问题,我们或许可以提供帮助。
标签: c++ oop pointers constants