Cannot convert 'this' pointer from 'const Line' to 'Line &' explanation?
This method:
bool Point::Intersects(const Line& line) const {
return (line.ContainsPoint(*this, false));
}
causes this error: cannot convert 'this' pointer from 'const Line' to 'Line &' This change:
bool Point::Intersects(const Line& line) const {
return const_cast<Line&>(line).ContainsPoint(*this, false);
}
fixes the error, but doesn't seem the right way to fix the issue. Why is the original method considered an error?
If it helps, ContainsPoint(const Point& point, bool isInfinite)
is non-const and all methods it calls are non-const as well.
Solution 1:
You actually provided the answer yourself, in a sense.
In your Intersects
method, the parameter line
is declared const
. This restricts how you can use this variable. Specifically, you can only call const
methods on it, and you can only pass it to methods expecting a const
Line object.
However, you pointed out that ContainsPoint
is not declared const
. So it does not satisfy the requirement mention above (i.e. calling a non-const
method on a const
object is not allowed). This is why the original method generates the error, and it also explains why your second version works, since the restriction is alleviated via the const_cast
.
The real problem is in the declaration of ContainsPoint
(and probably also with whatever methods it calls, as they are also non-const
). There appears to be a large design flaw here. Since the purpose of ContainsPoint
is to check whether or not a Point
is on a Line
, side-effects will be unexpected. So there should be no reason for it to not be a const
method. In fact (and your example shows this), users of Line
would expect ContainsPoint
to be a const
method. Therefore, the real solution is to change the design of the Line
class so that methods like ContainsPoint
are declared const
, and only methods which clearly change the state of an instance are left non-const
Solution 2:
In this case you are calling a non-const method on a const reference which isn't allowed. You have two options:
- Do what you did and
const_cast
- Make
ContainsPoint
a const method
Solution 3:
The problem is in fact a simple one:
you have a class A, with a non-const method foo(), you are invoking non-const method foo() through a ref to const A.
const A& a = ...;
a.foo(); // failed
That's what const aimed for: a const variable means, it is declared not going to be changed. While foo() "is going to change itself" (as foo() is a non-const method, which means: "I am legal to change thing inside"), that's why compiler complains: you have a const var (a), but you are going to change its content (thru foo())
The way to solve is straight forward, but you should know which way is correct to do:
1) If you are sure that foo() should be legal to be invoked through const ref etc, you should declare it as a const method: A::foo() const {...}
2) If you know that foo() is not appropriate to make const, you should consider
2.1) review "a" to see if it is more appropriate to make non-const, or
2.2) find another const method in A that did the work.
(There are some other way like using mutable, or const_cast, but that's not the way to go for 99.9% of time. So I didn't mention here)