Что может изменить метод const? - PullRequest
22 голосов
/ 28 июля 2011
Методы

C ++ позволяют квалификатору const указывать, что метод не изменяется объектом. Но что это значит? Например. если переменные экземпляра являются указателями, означает ли это, что указатели не изменились или что память, на которую они указывают, не изменилась?

Конкретно, вот минимальный пример класса

class myclass {
  int * data;

  myclass() {
    data = new int[10];
  }

  ~myclass() {
    delete [] data;
  }

  void set(const int index) const {
    data[index] = 1;
  }
};

Правильно ли метод set квалифицируется как const? Он не меняет переменную-член data, но, несомненно, меняет содержимое массива.

Ответы [ 5 ]

21 голосов
/ 28 июля 2011

Что может изменить метод const?

Без явного отбрасывания константы метод const может измениться:

  • mutableчлены данных и
  • любые данные, к которым у класса нет доступа const, независимо от того, доступны ли эти данные:
    • через переменные-члены, которые являются указателями или ссылками,
    • через указатели или ссылки, передаваемые в качестве параметров функции,
    • через указатели или ссылки, возвращаемые функциями,
    • непосредственно в пространстве имен или классе (для статики), в котором оно содержится.

Для членов типа class / struct / union он зависит от постоянства их функций-членов, чтобы определить, какие операции должны быть разрешены.(Он также может изменять любые неконстантные локальные переменные и параметры по значению, но я знаю, что это не то, что вас интересует).

Он может вызывать другие const методы, которые будут иметь такие же возможностии ограничения.

Например.если переменные экземпляра являются указателями, означает ли это, что указатели не изменены, или также что память, на которую они указывают, не изменилась?

Это означает, что указатели не могут быть (легко /случайно) поменял. не означает, что указанная память не может быть изменена.

На что вы наткнулись - это логическая некорректность функции const, изменяющей указанную или на которую ссылаютсяДанные концептуально принадлежат объекту.Как вы обнаружили, компилятор не обеспечивает корректность const, которую вы можете здесь ожидать.Это немного опасно, но означает, что constness не нужно явно удалять для указателей / ссылок на другие объекты, которые могут быть изменены как побочный эффект const функции .Например, объект регистрации.(Как правило, такие объекты не являются логически «принадлежащими» объектам, чья функция const работает с ними.) Ключевым моментом является то, что компилятор не может надежно различать тип логического владения, которое объект имеет над указанными данными.Таким образом, он должен угадать так или иначе и позволить программисту либо переопределить, либо не быть защищенным const -ness.C ++ отказывается от защиты.

Интересно, я слышал, что язык D Уолтера Брайта переворачивает это значение по умолчанию, делая указанными данные const по умолчанию в функциях const.Это кажется мне более безопасным, хотя трудно представить, как часто в конечном итоге нужно будет явно отбрасывать константу, чтобы получить желаемые побочные эффекты, и будет ли это чувствовать себя достаточно точно или досадно многословно.

15 голосов
/ 28 июля 2011

Вкратце, это означает, что тип this имеет значение const T * внутри константных функций-членов, где T - ваш класс, а в неквалифицированных функциях - T *.

Ваш методset не меняет data, поэтому его можно квалифицировать как const.Другими словами, myclass::data доступен как this->data и имеет тип int * const.

6 голосов
/ 28 июля 2011

У этого вопроса есть два аспекта:

  1. что означает const для компилятора?
  2. как применяется const, когда он не может быть проверен компилятором?

Вопрос 1

Первый довольно прост.Компилятор проверяет, что никакие члены данных не изменены (если они не квалифицированы как mutable).Он проверяет это рекурсивно: для любых пользовательских типов он проверяет, что неконстантные методы не вызываются.Для встроенных типов проверяется, что они не назначены.

Преобразование для указателей: T* в T*const (указатель const), а не const T* (указатель на const).Это означает, что компилятор не проверяет, что указанный объект не изменен.Очевидно, это приводит к вопросу 2.

Вопрос 2

Как применяется const, когда компилятор не проверяет его?Это означает, что это должно означать для вашего приложения.Это обычно называют логическим постоянным.Когда использовать const по отношению к логическому постоянству - это субъект дискуссия .

0 голосов
/ 28 июля 2011

const при применении к методу означает:

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

Поскольку это относится к указателям.Это означает, что указатель (если он является частью состояния) не может быть изменен.Но объект, на который указывает указатель, является частью другого объекта, поэтому вы можете вызывать не затратные методы для этого объекта (так как он не является частью состояния этого объекта).

0 голосов
/ 28 июля 2011

const в основном предотвращает изменение значений членов экземпляра класса внутри функции. Это полезно для более понятного интерфейса, но накладывает ограничения, например, при использовании наследования. Иногда это немного обманывает (или много на самом деле), как в приведенном вами примере.

const будет наиболее подходящим для функций Get, где очевидно, что вызывающая сторона читает значение и не намерена изменять состояние объекта. В этом случае вы хотели бы ограничить унаследованные реализации, а также придерживаться const ness, чтобы избежать путаницы и скрытых ошибок при использовании полиморфизма.

Например

class A{
     int i;
   public:
     virtual int GetI() {return i;};
}

class B : public A{
   public:
     int GetI() { i = i*2; return i;}; // undesirable
}

изменяя А на:

virtual int GetI() const {return i;};

решает проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...