Почему «const» ведет себя по-разному в этих двух случаях? - PullRequest
0 голосов
/ 28 октября 2019

У меня есть вопрос о том, почему определенная вещь может быть скомпилирована, когда сделано «в один шаг», но не может, когда сделано «в два шага». У меня есть три класса:

class Time {
  int mTime;

  int Time::getTimeAsUnix() const {return mTime;}
}

class Travel {
  Time mTimestamp;

  const Time& Travel::getTime() const { return mTimestamp; }
  Time& Travel::getTime() { return mTimestamp; }
}

class Analysis : public Travel {

  int Analysis::getUnixTime() const {
    // Time& t = Travel::getTime();
    // return t.getTimeAsUnix();     // This does NOT compile

    return Travel::getTime().getTimeAsUnix();  // This compiles
  }
}

Кто-нибудь знает, почему в классе Analysis некомментируемый подход компилируется, в то время как комментированный подход дает мне мгновенную "ошибку c ++: привязка« const Time »кссылка типа 'Time &' сбрасывает квалификаторы " когда я пытаюсь?

Разве это не одно и то же при исполнении ??

Ответы [ 3 ]

5 голосов
/ 28 октября 2019

Строка

Time& t = Travel::getTime();

должна быть

const Time& t = Travel::getTime();

, чтобы она работала. Причина, по которой это необходимо, заключается в том, что вы находитесь внутри функции, удовлетворяющей const. Когда вы находитесь в функции с квалификацией const, все члены класса считаются const. Это означает, что когда вы вызываете getTime, вы вызываете

const Time& Travel::getTime() const { return mTimestamp; }

версию функции. Попытка присвоить const Time& для Time& не будет работать, потому что вы удалили бы константу возвращаемого типа.

4 голосов
/ 28 октября 2019

В этом определении функции, где вы должны удалить Analysis::

  int Analysis::getUnixTime() const {
     Time& t = Travel::getTime();
     return t.getTimeAsUnix();  
  }

, вызывается функция

const Time& Travel::getTime() const { return mTimestamp; }

, которая возвращает постоянную ссылку. Именно эта перегруженная функция используется потому, что функция getUnixTime объявлена ​​как постоянная функция-член.

Однако постоянная ссылка присваивается непостоянной ссылке

     Time& t = Travel::getTime();

, поэтому компиляторвыдает ошибку.

1 голос
/ 28 октября 2019

Хорошо, давайте разберем рабочую версию:

int Analysis::getUnixTime() const { // (1)
    // (2) --------v        v----- (3)
    return Travel::getTime().getTimeAsUnix();
}

При (1) функция getUnixTime определена для работы с постоянным экземпляром. Это означает, что вы можете вызывать только другие постоянные функции и не можете изменять никакие переменные-члены.

При (2) вызывается Travel::getTime(). Это вызов нестатической функции-члена , исключающей ее синтаксис. Но это нормально, это понятно и вызывает const версию функции, которая возвращает const Time&. Ссылка на постоянный объект Time.

При (3) функция-член getTimeAsUnix вызывается для const Time&. Это идеально, потому что Time имеет функцию-член, названную таким образом, которая помечена для работы с постоянными объектами.

Таким образом, как вы видите, все объекты постоянны, и вы вызываете только постоянную функцию.


Что пошло не так, когда вы разбили код на две строки?

Давайте посмотрим на первую строку в теле вашей функции:

Time& t = Travel::getTime();

Как мы уже говорили, Travel::getTime() вызывает нестатическую функцию-член . Поскольку this является константным объектом (вы находитесь в функции const), то вызывается константная версия getTime, как и раньше.

Тип возврата const getTime равен * 1039. *.

Тогда вы делаете Time& t =. Это где вы ошибка. const Time& не может быть изменено. A Time& можно изменить. Если вы ссылаетесь на постоянный объект с помощью изменяемой ссылки, то вы сможете изменить постоянный объект. Язык запрещает это!

Чтобы это исправить, просто используйте постоянные ссылки:

const Time& t = Travel::getTime();
...