我想在下面的课程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
。
在这种情况下,有没有办法进行方法链接?
答案 0 :(得分:5)
您可以提供两个成员函数,一个const
和一个非const
。 const
将调用Point const
,const
上的Point
非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;
}
}
:
{{1}}
答案 1 :(得分:3)
IMO你不能正确理解const方法可以做什么。如果const方法向对象返回非常量referance,则它不是常量方法。
因此,在您的情况下,您只需从print方法中返回任何内容,并在链接结束时使用它
p.moveX(10).moveY(11).print();
。
UPD。或者,如果您有可能在课程中添加一些新的const方法,则可以返回const Point&
。
答案 2 :(得分:0)
您可以在返回时使用const_cast
(即return const_cast<Point&>(*this)
) - 这将确保您的方法无法修改对象,但调用者将能够修改它。
答案 3 :(得分:-1)
失败的原因是在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()
。这对你来说可能不是问题(你为什么要两次打印相同的值),只是通常知道的东西。