Не удается преобразовать указатель «этот» из «константной строки» в объяснение «Строка и»?

Этот метод:

bool Point::Intersects(const Line& line) const {
    return (line.ContainsPoint(*this, false));
}

вызывает эту ошибку: невозможно преобразовать указатель «this» из «const Line» в «Line &». Это изменение:

bool Point::Intersects(const Line& line) const {
    return const_cast<Line&>(line).ContainsPoint(*this, false);
}

исправляет ошибку, но не кажется правильным способом исправить проблему. Почему оригинальный метод считается ошибкой?

Если это поможет, ContainsPoint(const Point& point, bool isInfinite) неконстантен, и все методы, которые он вызывает, также неконстантны.


person Casey    schedule 08.07.2011    source источник
comment
@iammilind: у него есть прототип в последнем абзаце.   -  person Ken Wayne VanderLinde    schedule 08.07.2011


Ответы (3)


Вы фактически сами дали ответ, в некотором смысле.

В вашем методе Intersects параметр line объявлен как const. Это ограничивает использование этой переменной. В частности, вы можете вызывать только const методы для него, и вы можете передавать его только методам, ожидающим объект const Line.

Однако вы указали, что ContainsPoint не объявляется const. Таким образом, он не удовлетворяет упомянутому выше требованию (т. е. вызов метода, отличного от const, для объекта const не допускается). Вот почему исходный метод генерирует ошибку, а также объясняет, почему работает ваша вторая версия, поскольку ограничение снимается с помощью const_cast.

Настоящая проблема заключается в объявлении ContainsPoint (и, вероятно, также в любых методах, которые он вызывает, поскольку они также не являются const). Здесь, видимо, большой конструктивный недостаток. Поскольку цель ContainsPoint состоит в том, чтобы проверить, находится ли Point на Line, побочные эффекты будут неожиданными. Так что не должно быть никаких причин, чтобы это не был метод const. Фактически (и ваш пример показывает это), пользователи Line ожидают, что ContainsPoint будет методом const. Следовательно, реальное решение состоит в том, чтобы изменить дизайн класса Line таким образом, чтобы методы, подобные ContainsPoint, объявлялись const, а только методы, явно изменяющие состояние экземпляра, оставались не-const.

person Ken Wayne VanderLinde    schedule 08.07.2011

В этом случае вы вызываете неконстантный метод для константной ссылки, которая не разрешена. У вас есть два варианта:

  1. Делайте то, что делали, и const_cast
  2. Сделать ContainsPoint константным методом
person Andrew White    schedule 08.07.2011
comment
Нет, не (1). Определенно (2). Или сделайте локальную (неконстантную) копию line и вызовите копию. Но никогда не используйте const_cast для удаления const из объекта, если вы его не добавили. Всегда. - person Ben Voigt; 08.07.2011
comment
Мне придется сделать то, что я сделал. Создание ConstPoint константным методом вызовет цепную реакцию в коде константности каждого последующего метода. Возникает ли ошибка, потому что создание строки как константы является обещанием не изменять ее, и когда я пытаюсь вызвать неконстантный метод, компилятор не может ЗНАТЬ, что вызываемый метод изменяет его, поэтому он помечает ошибку? - person Casey; 08.07.2011
comment
@Бен: Согласен. Я видел, как многие люди используют const_cast многими неуместными способами. Просто хочу отметить, что если у вас есть метод, который концептуально является постоянным, но все еще нуждается в изменении некоторого частного состояния, рассмотрите возможность использования ключевого слова mutable. Я нахожу это отличной функцией, особенно при добавлении чего-то вроде запоминания к методам, которые в остальном являются постоянными. - person Ken Wayne VanderLinde; 08.07.2011
comment
Я бы настоятельно рекомендовал сделать ConstPoint константой, похоже, так и должно быть. И если я правильно помню, метод const может принимать неконстантную ссылку, но обратное неверно. - person Andrew White; 08.07.2011
comment
@Casey: Вот и все. Компилятор не сделает вывод, что метод const, вы должны сказать ему об этом. @Andrew: Даже неконстантный метод может принимать константные ссылки. Ключевое слово const после заголовка функции добавляет только const-ность текущему экземпляру и его членам/ - person Ken Wayne VanderLinde; 08.07.2011
comment
@Andrew: Извините, я думаю, что неправильно истолковал то, что вы сказали. Вы правы в том, что вызов метода const для неконстантного экземпляра работает, а наоборот — нет. - person Ken Wayne VanderLinde; 08.07.2011
comment
Константная корректность повышает безопасность вашего кода. Я бы получил корректность const прямо сейчас, потому что это только становится снежным комом и становится все труднее по мере роста вашего проекта. parashift.com/c++-faq-lite/const-correctness.html< /а> - person David Brown; 08.07.2011
comment
@Casey - иногда цепной реакции избежать нельзя. Это результат неправильного выбора в начале процесса. - person Mark Ransom; 08.07.2011
comment
Кроме того, чем раньше вы столкнетесь с ситуацией, связанной с цепной реакцией, тем раньше вы научитесь рассматривать const-коррекцию (и другие проблемы проектирования) как предусмотрительность, а не запоздалую мысль (по крайней мере, я на это надеюсь!!). - person Ken Wayne VanderLinde; 08.07.2011

Проблема на самом деле простая:

у вас есть класс A с неконстантным методом foo(), вы вызываете неконстантный метод foo() через ссылку на константу A.

const A& a = ...;
a.foo();  // failed

Это то, к чему стремился const: переменная const означает, что она объявлена ​​​​не подлежащей изменению. В то время как foo() «собирается изменить себя» (поскольку foo() является неконстантным методом, что означает: «Я имею право изменять что-то внутри»), поэтому компилятор жалуется: у вас есть const var (a) , но вы собираетесь изменить его содержимое (через foo())

Способ решения прост, но вы должны знать, какой путь правильный:

1) Если вы уверены, что foo() должно быть разрешено для вызова через const ref и т. д., вы должны объявить его как метод const: A::foo() const {...}

2) Если вы знаете, что foo() не подходит для создания const, вам следует подумать

2.1) просмотрите «a», чтобы увидеть, не является ли более подходящим сделать неконстантным, или

2.2) найти другой метод const в A, который выполнил эту работу.

(Есть и другой способ, например, использование mutable или const_cast, но это не тот способ, который подходит для 99,9% времени. Поэтому я не упомянул здесь)

person Adrian Shum    schedule 08.07.2011