从 const 成员函数返回 'this' 作为非常量

Return 'this' as non-const from const member function

本文关键字:非常 常量 this const 返回 成员 函数      更新时间:2023-10-16

我想在下面的Point上进行方法链接。

#include <iostream>
class Point {
  public:
    Point(int x, int y): _x(x), _y(y) {}
    Point& moveX(int x);
    Point& moveY(int y);
    Point& print() const;
  ...
};
...
Point& Point::print() const {
  std::cout << "(" << _x << "," << _y << ")" << std::endl;
  return *this;  // Compile fails
}

我认为将print()标记为const成员功能是有意义的,因为它只是打印内部成员。但是,我想在下面的非const和const函数之间进行方法链接。

int main() {
  Point p(1,1);
  p.moveX(10).print().moveY(11); // method chaining
}

因此,我必须将this返回为非CONST,但它未能使汇编失败,因为在我的理解中,成员被标记为const,包括const成员函数中的this

有没有办法在这种情况下进行方法链接?

您可以提供两个成员功能,一个const和一个非constconst将在 Point const上调用一个 const CC_11。

class Point {
public:
    Point(int x, int y): _x(x), _y(y) {}
    Point& moveX(int x);
    Point& moveY(int y);
    Point& print();
    Point const& print() const;
    ...
};

作为一个侧节点,最好过载std::ostream& operator<<(std::ostream&, Point const&),因此您可以与任何输出流一起使用,而不仅仅是std::cout

class Point {
    ...
private:
    friend std::ostream& operator<<(std::ostream& stream, Point const& point) {
        stream << "(" << point._x << "," << point._y << ")";
        return stream;
    }
}

imo您不正确理解const方法可以做什么。如果const方法返回非恒定的引用对您的对象,则不是恒定的方法。

因此,在您的情况下,您可以简单地从打印方法中返回任何内容,然后在链接结束时使用它 p.moveX(10).moveY(11).print();

upd。或者,如果有可能在类中添加一些新的const方法,则可以返回const Point&

返回时可以使用const_cast(即return const_cast<Point&>(*this)) - 这将确保您的方法无法修改对象,但是呼叫者将能够修改它。

失败的原因是const成员函数内部this实际上是const Point*,而不是Point*。因此,您正在尝试从const指针初始化非const参考。并不是说编译器不相信您,而是一次要求两次不兼容的事情。

我认为,这是const_cast的有效用途很少。通常,使用const_cast几乎总是设计错误的迹象,或者更糟的是编程错误。
在这里,该函数确实是const,应该是const,但是没有理由您之后您不应该链接某些非const,因此可以说要做这样的事情是合法的。

确实要注意,尽管该功能严格是const(相对于对象而言,其使用IO函数的用途不是太多!),您应该考虑的一件事是,在某些(罕见的)情况下,可能会导致它在不执行您想要的代码中。允许编译器缓存const功能的结果,并省略对同一const功能的另一个调用(因为您承诺将不会更改任何内容)。因此,可以将some_point.Print().Print();优化到some_point.Print()中。这对您来说可能不是问题(为什么要两次打印相同的值),只是一般来说知道的东西。