C++ 重复、常量和非常量、吸气剂的优雅解决方案?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/856542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 17:36:39  来源:igfitidea点击:

Elegant solution to duplicate, const and non-const, getters?

c++const

提问by Michael

Don't you hate it when you have

当你有的时候,你不讨厌它吗

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

We can't implement either of this methods with the other one, because you can't call the non-constversion from the constversion (compiler error). A cast will be required to call the constversion from the non-constone.

我们不能用另一种方法来实现这两种方法中的任何一种,因为你不能constconst版本中调用非版本(编译器错误)。将需要演员来调用const非版本的版本const

Is there a real elegant solution to this, if not, what is the closest to one?

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

采纳答案by CAdaker

I recall from one of the Effective C++ books that the way to do it is to implement the non-const version by casting away the const from the other function.

我记得在其中一本 Effective C++ 书籍中,这样做的方法是通过从另一个函数中丢弃 const 来实现非常量版本。

It's not particularly pretty, but it is safe. Since the member function calling it is non-const, the object itself is non-const, and casting away the const is allowed.

它不是特别漂亮,但很安全。由于调用它的成员函数是非常量的,所以对象本身也是非常量的,并且允许抛弃常量。

class Foo
{
public:
    const int& get() const
    {
        //non-trivial work
        return foo;
    }

    int& get()
    {
        return const_cast<int&>(const_cast<const Foo*>(this)->get());
    }
};

回答by Steve Jessop

How about:

怎么样:

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

Obviously you'll still have object code duplication, but no source code duplication. Unlike the const_cast approach, the compiler will check your const-correctness for both versions of the method.

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

You probably need to declare the two interesting instantiations of BigChunk as friends of the class. This is a good use of friend, since the friend functions are hidden away close to the friendee, so there is no risk of unconstrained coupling (ooh-er!). But I will not attempt the syntax for doing so right now. Feel free to add.

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

Chances are that BigChunk needs to deference self, in which case the above order of definition isn't going to work very well, and some forward declarations will be needed to sort it out.

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

Also, in order to avoid some numpty finding BigChunk in the header and deciding to instantiate and call it even though it's morally private, you can move the whole lot into the cpp file for FooBar. In an anonymous namespace. With internal linkage. And a sign saying "beware of the leopard".

此外,为了避免在标头中找到 BigChunk 并决定实例化并调用它,即使它在道德上是私有的,为了避免一些笨拙的方法,您可以将整个批次移动到 FooBar 的 cpp 文件中。在匿名命名空间中。有内部联动。还有一个牌子,上面写着“小心豹子”。

回答by Matthew Flaschen

I would cast the const to the non-const (second option).

我会将 const 转换为非常量(第二个选项)。

回答by markh44

Try to eliminate the getters by refactoring your code. Use friend functions or classes if only a very small number of other things needs the Something.

尝试通过重构代码来消除 getter。如果只有极少数其他事物需要Something,请使用友元函数或类。

In general, Getters and Setters break encapsulation because the data is exposed to the world. Using friend only exposes data to a select few, so gives better encapsulation.

一般来说,Getter 和 Setter 会破坏封装,因为数据是公开的。使用friend只将数据暴露给少数几个,因此提供更好的封装。

Of course, this is not always possible so you may be stuck with the getters. At the very least, most or all of the "non-trivial chunk of code" should be in one or more private functions, called by both getters.

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

回答by markh44

Why not just pull the common code out into a separate, private function, and then have the other two call that?

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

回答by swongu

The constreference to the object makes sense (you're putting a restriction on read-only access to that object), but if you need to allow a non-constreference, you might as well make the member public.

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

I believe this is a la Scott Meyers (Efficient C++).

我相信这是一个 la Scott Meyers(高效 C++)。

回答by Abhay

The concept of 'const' is there for a reason. To me it establishes a very important contract based on which further instructions of a program are written. But you can do something on the following lines :-

'const' 的概念是有原因的。对我来说,它建立了一个非常重要的合同,基于该合同编写程序的进一步说明。但是你可以在以下几行做一些事情:-

  1. make your member 'mutable'
  2. make the 'getters' const
  3. return non-const reference
  1. 使您的成员“可变”
  2. 使“吸气剂”成为常量
  3. 返回非常量引用

With this, one can use a const reference on the LHS if you need to maintain the const functionality where you are using the getter along with the non-const usage(dangerous). But the onus is now on the programmer to maintain class invariants.

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

As has been said in SO before, casting away constness of an originally defined const object and using it is an U.B. So i would not use casts. Also making a non-const object const and then again casting away constness would not look too good.

正如之前在 SO 中所说的那样,抛弃最初定义的 const 对象的常量性并使用它是一个 UB 所以我不会使用强制转换。同样制作一个非常量对象 const 然后再次抛弃 constness 看起来不太好。

Another coding guideline that I have seen used in some teams is:-

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

  • If a member variable needs to be modified outside the class, always return a pointer to it via a non-const member function.
  • No member functions can return non-const references. Only const references are allowed form const member functions.
  • 如果需要在类外修改成员变量,请始终通过非常量成员函数返回指向它的指针。
  • 任何成员函数都不能返回非常量引用。const 成员函数中只允许使用 const 引用。

This allows some consistency in the overall codebase and the caller can clearly see which calls can modify the member variable.

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

回答by Matthew

I dare suggest using the preprocessor:

我敢建议使用预处理器:

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