复制,常量和非常量,getter 的优雅解决方案?

难道你不讨厌

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版本。

有没有一个真正优雅的解决方案,如果没有,什么是最接近的一个?

74123 次浏览

我将把 const 转换为 non-const (第二个选项)。

尝试通过重构代码来消除 getter。如果只有很少数量的其他东西需要某些东西,那么使用好友函数或类。

通常,Getters 和 Setters 会破坏封装,因为数据是公开的。使用 friend 只将数据暴露给选定的少数人,因此可以提供更好的封装。

当然,这并不总是可能的,因此您可能会被困在 getter 中。至少,大部分或全部“非平凡的代码块”应该在一个或多个私有函数中,由两个 getter 都调用。

“ const”的概念之所以存在是有原因的。对我来说,它建立了一个非常重要的合同,在此基础上编写程序的进一步指令。但是你可以在以下几行做一些事情:-

  1. 让你的成员“易变”
  2. 让“得到者”成为常数
  3. 返回非常量引用

有了这个,如果您需要维护 const 功能,您可以在 LHS 上使用 const 引用,其中使用 getter 以及非 const 使用(危险)。但是现在程序员有责任维护类的不变量。

正如以前在 SO 中所说的,抛开最初定义的 const 对象的常量,使用它就是一个 U.B. 。所以我不会用石膏。另外,使一个非常量对象常量,然后再抛弃常量将不会看起来太好。

我在一些团队中看到的另一个编码指南是:-

  • 如果需要在类之外修改成员变量,则始终 通过非常数成员函数返回指向它的指针。
  • 任何成员函数都不能返回非常量引用 允许引用形式为 const 成员函数。

这使得整个代码库具有一定的一致性,调用方可以清楚地看到哪些调用可以修改成员变量。

对该对象的 const引用是有意义的(您对该对象的只读访问设置了限制) ,但是如果您需要允许非 const引用,那么您不妨将该成员设置为 public。

我相信这就是 Scott Meyers (高效 C + +)。

我记得在一本有效的 C + + 书籍中提到过,实现这个功能的方法是通过抛弃其他函数中的 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());
}
};

这个怎么样:

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 方法不同,编译器会检查两个版本的方法的常量正确性。

您可能需要将 BigChunk 的两个有趣的实例声明为类的朋友。这是好友的一个很好的用法,因为好友函数隐藏在靠近好友的地方,所以不存在无约束耦合的风险(噢!).但是我现在不会尝试这样做的语法。随便加。

很可能 BigChunk 需要遵从 self,在这种情况下,上面的定义顺序不会很好地工作,需要一些前向声明来解决这个问题。

另外,为了避免在头文件中发现 BigChunk 并决定实例化它并调用它(即使它在道德上是私有的) ,您可以将所有这些内容移动到 FooBar 的 cpp 文件中。在匿名命名空间中。内部连接。还有一个写着“小心豹子”的牌子。

为什么不将公共代码提取到一个单独的私有函数中,然后让另外两个函数调用它呢?

我大胆建议使用预处理器:

#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)
};