复制,常量和非常量,吸气剂的优雅解决方案?

时间:2009-05-13 07:25:09

标签: c++ const

当你有

时,你不恨它吗?
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版本。

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

8 个答案:

答案 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'的概念是有原因的。对我来说,它建立了一个非常重要的合同,在此基础上编写了程序的进一步指令。但是你可以在以下几行做点什么: -

  1. 让你的会员'变得''
  2. 制作'getters'const
  3. 返回非const引用
  4. 有了这个,你可以在LHS上使用const引用,如果你需要维护const功能,你在使用getter和非const用法(危险)。但现在程序员有责任维护类不变量。

    如前所述,抛弃原始定义的const对象的常量并使用它是U.B.所以我不会使用演员阵容。还使非const对象const然后再次抛弃constness看起来不太好。

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

    • 如果需要在类外修改成员变量,请始终 通过非const成员函数返回指向它的指针。
    • 没有成员函数可以返回非const引用。只有const 允许引用形式为const成员函数。

    这允许整个代码库中的一些一致性,并且调用者可以清楚地看到哪些调用可以修改成员变量。

答案 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)
};