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

Mic*_*ael 114 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我们无法使用另一个方法实现这两种方法,因为您无法constconst版本中调用非版本(编译器错误).演员将被要求const从非const一个版本调用该版本.

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

CAd*_*ker 104

我从其中一本Effective 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());
    }
};
Run Code Online (Sandbox Code Playgroud)

  • `static_cast <const Foo*>(this)`应该是`const_cast <const Foo*>(this)`. (20认同)
  • 只要foo不是(并且永远不会成为)const成员,这是安全的.如果确实如此,那么你应该重新实现get的非const版本(或者回到绘图板而不是make foo const),但你实际做的是没有注意到问题,因为它全部编译好. (12认同)
  • "一个const成员".或者const从调用返回到其他函数.基本上编译器认为它是以const形式返回的,但"真的"它因为强制转换而返回为非const.因此,在"this"是非const的情况下,它必须真正是非const,并且编译器无法帮助您强制执行. (6认同)
  • 从答案文本:**因为调用它的成员函数是非const,所以对象本身是非const的,并且允许抛弃const.**多次阅读此语句后,我__________理解为什么这种方法是安全和正确. (6认同)
  • 是的,但如果你不知道,编译器会告诉你代码是否有效.如果你演员,你必须自己解决.我并不是说这是不可能的,或者这不一定是个坏主意,但C++程序员确实倾向于依赖编译器,特别是对于const-correctness和其他形式的类型安全.这就是它的用途. (4认同)
  • 当然,这个想法是"非平凡的工作"明显长于非const方法中的单线程.否则它确实毫无意义. (4认同)
  • @Jeandard:`const`可以在没有强制转换的情况下隐式添加,所以`static_cast`什么都不做,就像`const_cast`一样.也就是说,在这种情况下两者之间没有任何区别,因为它们实际上都没有做任何事情.但是为了便于阅读,应该使用反映实际发生的类型变化的演员表. (3认同)
  • @ildjarn:应该吗?当你想要删除`const`或`volatile`限定符时你需要`const_cast`,但如果你想添加它们,`static_cast`就足够了. (2认同)

Ste*_*sop 27

怎么样:

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);
    }
};
Run Code Online (Sandbox Code Playgroud)

显然你仍然会有目标代码重复,但没有源代码重复.与const_cast方法不同,编译器将检查两种版本方法的const正确性.

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

有可能BigChunk需要尊重自己,在这种情况下,上面的定义顺序不会很好地工作,并且需要一些前向声明来解决它.

此外,为了避免在标题中找到BigChunk并决定实例化并调用它,即使它在道德上是私有的,你可以将整个批次移动到FooBar的cpp文件中.在匿名命名空间中.内部联系.还有一个标语"小心豹子".

  • @HelloGoodbye 您可以将函数声明为友元,而不是传递私有成员或创建 getter/setter,因为它在技术上是类的一部分。您可以将模板函数移至 cpp 文件并显式启动它来解决该问题。当然,这需要进一步的代码。 (2认同)

Mat*_*hen 7

我会将const转换为非const(第二个选项).

  • +1:我认为这是const_cast的少数有效用途之一 - 它肯定胜过代码重复和/或跳过各种各样的箍. (6认同)
  • 它会工作,但我不认为这非常优雅...... (2认同)
  • 如果`something`被声明为const,那么你将遇到一个问题,你不会注意到,因为你的程序仍在编译. (2认同)

小智 5

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

  • 问题是,如果私有函数是非常量的,那么const版本就不能调用它。相反,如果私有函数是const,则它不能返回`Something&`(假定返回的值是`Foo`的成员)。因此,Something&getSomething(int index)和const Something&getSomething(int index)const都不可能调用相同的私有方法。 (3认同)