让一个Foo
类包含一些const和非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。我快乐了。
但是现在我想有时使用带const Foo
个实例的Bar。好吧,这可能很容易,我只需要创建一个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方法)做一些令人讨厌的事情,同时允许非const Bar执行所有操作?
也许没有办法做到这一点,这是一个对象设计问题,但我没有看到一个简单的替代方案。
编辑:对于downvoters,你能否解释一下原因,我可以从你的言论中取得进展......
编辑2 :也许混淆真实的课程,恐惧Foo和Bar是一个坏主意,我只是想简化一些事情。
所以Foo
实际上是一种分子(实际上是一种蛋白质),它含有原子(许多是蛋白质)。能够选择一些原子是创建Bar的原因,它是SelectionOfAtoms
。
有时可以方便地选择所有氢和氧原子,因此Bar实现了联合和交叉。我希望能够提取这些原子,以便SelectionOfAtoms从所选原子实现createNewMolecule()方法。因此,它需要一种方法来引用原始分子(也许某种副本会在这里做,但可能不符合下面的其他要求)。
但我最近觉得需要修改选择的原子,同时保持其他原子不被修改。通过SelectionOfAtoms(Bar)这么做是很方便的:它已经知道在哪里找到原子(使用指针)和这些原子的索引(内部实现细节),所以改变原子所需的一切几乎已经在这里,除了我可以要么只在Molecule上使用Selection(非const),要么在const Molecule上工作,忘记修改它们或进入const_cast恐怖。
我确定这是一个非常糟糕的设计,但它已经存在,它肯定会得到很大改善。
答案 0 :(得分:3)
使用STL作为指导,将您的分子视为容器,并选择迭代器或迭代器范围。
现在,在这个方案中,你有单独的类型用于const和非const选择/迭代器,这是有道理的,因为它们具有不同的语义。使constness成为模板参数可能是一种虚假的经济,除非选择的代码比你建议的要多得多。
现在,你从const或非const molecule
开始,你静静地知道你已经获得了const_selection
或(非常){{1} }}
答案 1 :(得分:-1)
它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);
}