当你有
时,你不恨它吗?class Foobar {
public:
Something& getSomething(int index) {
// big, non-trivial chunk of code...
return something;
}
const Something& getSomething(int index) const {
// big, non-trivial chunk of code...
return something;
}
}
我们无法使用另一个方法实现这两种方法,因为您无法从const
版本调用非const
版本(编译器错误)。
演员将需要从非const
版本调用const
版本。
是否有一个真正优雅的解决方案,如果没有,最接近一个?
答案 0 :(得分:98)
我从其中一本有效的C ++书中回忆说,这样做的方法是通过从另一个函数中抛弃const来实现非const版本。
它不是特别漂亮,但它是安全的。由于调用它的成员函数是非const的,因此对象本身是非const的,并且允许抛弃const。
class Foo
{
public:
const int& get() const
{
//non-trivial work
return foo;
}
int& get()
{
return const_cast<int&>(const_cast<const Foo*>(this)->get());
}
};
答案 1 :(得分:26)
怎么样:
template<typename IN, typename OUT>
OUT BigChunk(IN self, int index) {
// big, non-trivial chunk of code...
return something;
}
struct FooBar {
Something &getSomething(int index) {
return BigChunk<FooBar*, Something&>(this,index);
}
const Something &getSomething(int index) const {
return BigChunk<const FooBar*, const Something&>(this,index);
}
};
显然,你仍然会有目标代码重复,但没有源代码重复。与const_cast方法不同,编译器将检查方法的两个版本的const-correctness。
您可能需要将BigChunk的两个有趣实例声明为该类的朋友。这是一个很好用的朋友,因为朋友的功能隐藏在靠近朋友的地方,所以不存在无约束耦合的风险(哦!)。但我现在不会尝试这样做的语法。随意添加。
有可能BigChunk需要尊重自己,在这种情况下,上面的定义顺序不会很好地工作,并且需要一些前向声明来解决它。
另外,为了避免在标题中找到BigChunk并决定实例化并调用它,即使它在道德上是私有的,你可以将整个批次移动到FooBar的cpp文件中。在匿名命名空间中。内部联系。还有一个标语“小心豹子”。
答案 2 :(得分:7)
我会将const转换为非const(第二个选项)。
答案 3 :(得分:5)
为什么不将公共代码拉出到一个单独的私有函数中,然后另外两个调用它?
答案 4 :(得分:4)
尝试通过重构代码来消除getter。如果只有极少数其他东西需要Something,请使用好友函数或类。
通常,Getters和Setter会破坏封装,因为数据会暴露给全世界。使用friend只会将数据暴露给少数几个,因此可以提供更好的封装。
当然,这并不总是可行的,所以你可能会被吸气剂困住。至少,大多数或所有“非平凡的代码块”应该在一个或多个私有函数中,由两个getter调用。
答案 5 :(得分:3)
const
对该对象的引用是有意义的(您对该对象的只读访问权限有限制),但如果您需要允许非const
引用,则可能并将会员公之于众。
我相信这是一个la Scott Meyers(高效C ++)。
答案 6 :(得分:2)
'const'的概念是有原因的。对我来说,它建立了一个非常重要的合同,在此基础上编写了程序的进一步指令。但是你可以在以下几行做点什么: -
有了这个,你可以在LHS上使用const引用,如果你需要维护const功能,你在使用getter和非const用法(危险)。但现在程序员有责任维护类不变量。
如前所述,抛弃原始定义的const对象的常量并使用它是U.B.所以我不会使用演员阵容。还使非const对象const然后再次抛弃constness看起来不太好。
我在一些团队中看到的另一个编码指南是: -
这允许整个代码库中的一些一致性,并且调用者可以清楚地看到哪些调用可以修改成员变量。
答案 7 :(得分:-2)
我敢建议使用预处理器:
#define ConstFunc(type_and_name, params, body) \
const type_and_name params const body \
type_and_name params body
class Something
{
};
class Foobar {
private:
Something something;
public:
#define getSomethingParams \
( \
int index \
)
#define getSomethingBody \
{ \
return something; \
}
ConstFunc(Something & getSomething, getSomethingParams, getSomethingBody)
};