【问题标题】:Enforce constness for pointed data in C++?对 C++ 中的指向数据强制执行 constness?
【发布时间】: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 ptr Bar 永远无法修改 Foo。我希望非 const Bar 对其Foo 执行任何操作,同时防止const Bar 调用修改ptr 指向的数据的方法。
  • 你可以做类似const_iterator/iterator的事情。 (也许让Bar 一个模板类使用一些policy)。
  • 噩梦从你输入const_cast的那一刻开始
  • Bar 实例是否需要修改Foo 对象的内容?还是他们只关心对象的身份(地址)?
  • 我知道在屋内开枪是个糟糕的决定,但我差点把沙发上的灯关掉……。如果您能回答上述评论中的问题,我们或许可以提供帮助。

标签: c++ oop pointers constants


【解决方案1】:

以 STL 为指导,将您的分子视为容器,并将您的选择视为迭代器或迭代器范围。

现在,在这个方案中,对于 const 和非 const 选择/迭代器,您将有单独的类型,这是有道理的,因为它们具有不同的语义。除非选择的代码比您建议的多得多,否则将 constness 作为模板参数可能是一种错误的经济方式。

现在,您从 const 或非 const molecule 开始,并且静态地知道您得到的是 const_selection 或(非 const)selection

【讨论】:

  • 要清楚,您建议创建类 Bar 和 const_Bar。对吗?
  • 是的,这是最简单的想法。
【解决方案2】:

Bar 不是很复杂,可以做成类模板。

template <typename FooType>
struct Bar
{

   FooType * p_foo;

   Bar (FooType& foo)
     : p_foo(&foo) {};

}

template <typename FooType>
Bar<FooType> makeBar(FooType& foo)
{
   return Bar<FooType>(foo);
}

【讨论】:

    猜你喜欢
    • 2019-03-07
    • 2011-08-22
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-05
    相关资源
    最近更新 更多