Вызов неконстантного метода для члена из константного метода - PullRequest
6 голосов
/ 19 декабря 2011

Я был удивлен, обнаружив эту "дыру" в "постоянстве":

#include <stdio.h>

class A
{
  int r ;
public:
  A():r(0){}

  void nonconst()
  {
    puts( "I am in ur nonconst method" ) ;
    r++;
  }
} ;

class B
{
  A a ;
  A* aPtr ;

public:
  B(){ aPtr = new A() ; }

  void go() const
  {
    //a.nonconst() ;      // illegal
    aPtr->nonconst() ;  //legal
  }
} ;

int main()
{
  B b ;
  b.go() ;
}

Таким образом, в основном из const метода B::go(), вы можете вызвать неконстантный функция-член (метко названная nonconst()), если указатель указывает на объект типа A.

Почему это так?Похоже, проблема (вроде как было в моем коде, где я ее нашел).

Ответы [ 3 ]

11 голосов
/ 19 декабря 2011

Когда и объект типа B является константным, то все его члены являются константными, что означает, что его два члена в течение B::go() фактически

A const a;
A * const aPtr;

Первыйпостоянный объект типа A, для которого вы можете вызывать только функции-члены const.Вторым, однако, является постоянный указатель на непостоянный A.Вы не могли бы по закону сказать aPtr = <anything> из функции B::go(), так как это изменило бы aPtr, который является постоянным.

Указатель на константу A будет объявлен как A const* aPtr или const A* aPtr, что сделает вызов непостоянной A::nonconst() недопустимым.

6 голосов
/ 19 декабря 2011

«Константность» объекта не распространяется на другие объекты через указатели.В вашем примере часть const - это либо весь объект a, либо указатель aPtr.Поскольку aPtr является A *, а не const A *, вам разрешается вызывать неконстантный метод.

При изменении

A* aPtr ;

на

const A* aPtr ;

тогда вы не сможете звонить aPtr->nonconst().

0 голосов
/ 19 декабря 2011

Определение языка const

Я был удивлен, обнаружив эту "дыру" в "постоянстве":

Нет ни одного.

const применяется равномерно ко всем членам класса: в const функции-члене класса C, this имеет тип const C *, поэтому для члена C::mem, объявленного как типT:

class C {
// ...
    T mem;
};

this->mem имеет тип const T.

Пожалуйста, выберите тип, чтобы различить, что является объявленным типом T и соответствующим типом, соответствующим константам для всехчлены.

Похоже, проблема (вроде как была в моем коде, где я ее нашел).

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

Вы должны записать свои ожидания, чтобы увидеть, что вы ожидали неоднородногоприложение, если const для различных типов.

Когда вы программируете, вы должны логически рассуждать.Вы должны делать выводы, а не ожидать их, когда нет логической причины.

Использование const правильно

Почему это так?

Ваши занятиябудучи названным A и B, довольно трудно понять, что составляет логическое состояние, а что нет.;) Вы задаете «моральный» вопрос (не вопрос только о легальных / нелегальных программах на C ++), а ваш фрагмент кода не имеет «морального» значения.Если вы действительно публикуете соответствующий код, мы можем сделать некоторые «моральные» суждения об этом.

Логическое состояние

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

Это означает , вам нужно определить, каково "логическое состояние" ваших экземпляров класса : это абстрактное понятие, и только вы можете определить его, потому что оноконцепция высокого уровня. «Логическое состояние» относится к проблеме, которую должен решить ваш класс.

Затем вы можете определить, какие переменные влияют на логическое состояние: способствует ли *(b.aPtr) логическому состоянию b?

Тесно связанные вопросы

Знаете ли вы о конструкторе копирования?

Об операторе назначения копирования?

О деструкторе?

...