Что означает модификатор const после объявления метода - страница 6

 
Константные методы
Константные методы отличаются тем, что не изменяют значений полей своего класса. Рассмотрим это на примере под названием CONSTFU:
// constfu.cpp
// применение константных методов
class aClass
{
private:
    int alpha;
public:
    void nonFunc()    // неконстантный метод
    { 
        alpha = 99;
    }      // корректно
    void conFunc()const   // константный метод
    { 
        alpha = 99;
    }    // ошибка: нельзя изменить значение поля
};

Обычный метод nonFunc() может изменить значение поля alpha, а константный метод conFunc() не может. Если со стороны последнего будет предпринята попытка изменить поле alpha, компилятор выдаст сообщение об ошибке.
Для того чтобы сделать функцию константной, необходимо указать ключевое слово const после прототипа функции, но до начала тела функции. Если объявление и определение функции разделены, то модификатор const необходимо указывать дважды — как при объявлении функции, так и при ее определении. Те методы, которые лишь считывают данные из поля класса, имеет смысл делать константными, поскольку у них нет необходимости изменять значения полей объектов класса.

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

Пример класса Distance

Для того чтобы не включать множество нововведений в одну программу, мы до сих пор не использовали в наших примерах константные методы. Однако существует немалое количество ситуаций, где применение константных методов было бы весьма полезным. Например, метод showdist() класса Distance, неоднократно фигурировавшего в наших примерах, следовало сделать константным, потому что он не изменяет (и не должен изменять!) полей того объекта, для которого он вызывается. Он предназначен лишь для вывода текущих значений полей на экран

...

взято из стр 250, Лафоре Р. - Объектно-ориентированное программирование в С++ (4-е изд.) 2004

 
Dmitry Fedoseev:

Это и имеется ввиду, потому-что в данном контексте о типе не ведется разговор. "Свой класс" - это очевидно, что свой экземпляр (т.е. объект).

 Член _x принадлежит тому же классу в котором находится метод bar.

C obj._x - здесь член _x находится в постороннем классе obj.

Мне кажется допустимым говорить про класс, а не экземпляр, потому-что очевидно, что _x относится к нашему классу который пишем, и obj.x к постороннему, который обрабатываем. 

Если уж говорить о терминологии ООП, тут вся терминология немного того (или даже много). 

Дмитрий, Вы понимаете, что если так говорить, у тех, кто впервые начнет знакомиться с ООП вот с такой терминологией крыша поедет!? 

Это и имеется ввиду, потому-что в данном контексте о типе не ведется разговор. "Свой класс" - это очевидно, что свой экземпляр (т.е. объект).

Это Вам, возможно, очевидно. Я вот читаю и думаю, как член _х может принадлежать классу, если класс - это инструкция, абстракция, как Вы сами сказали:

Форум по трейдингу, автоматическим торговым системам и тестированию торговых стратегий

Что означает модификатор const после объявления метода

Dmitry Fedoseev, 2016.02.01 19:06

Как может объект вызывать метод? Метод может вызываться из функции или из другого метода.

Вызывается не просто метод класса, а метод конкретного объекта. Сам по себе класс это абстракция.

C obj._x - здесь член _x находится в постороннем классе obj.

Вы серьезно не понимаете различий между классом и экземпляром класса!? Нельзя так говорить, ни в коем случае, потому что это у читающего вызовет взрыв мозга, и он подумает, что объект который вызвал метод и объект obj - это экземпляры разных классов, хотя они экземпляры одного класса (в приведенном Вами примере). 

Если уж говорить о терминологии ООП, тут вся терминология немного того (или даже много).  

Терминология тогда "немного того", когда не понимаешь с чем имеешь дело. Нужно просто ясно понимать что такое класс (инструкция), а что такое объект (экземпляр) класса. И тогда множество проблем отпадут сами собой. Видимо переубедить мне Вас не получится, так что дальше на эту тему дискутировать смысла не вижу. Очень жаль.
 
unreal:
Константные методы
Константные методы отличаются тем, что не изменяют значений полей своего класса. Рассмотрим это на примере под названием CONSTFU:
// constfu.cpp
// применение константных методов
class aClass
{
private:
    int alpha;
public:
    void nonFunc()    // неконстантный метод
    { 
        alpha = 99;
    }      // корректно
    void conFunc()const   // константный метод
    { 
        alpha = 99;
    }    // ошибка: нельзя изменить значение поля
};

Обычный метод nonFunc() может изменить значение поля alpha, а константный метод conFunc() не может. Если со стороны последнего будет предпринята попытка изменить поле alpha, компилятор выдаст сообщение об ошибке.
Для того чтобы сделать функцию константной, необходимо указать ключевое слово const после прототипа функции, но до начала тела функции. Если объявление и определение функции разделены, то модификатор const необходимо указывать дважды — как при объявлении функции, так и при ее определении. Те методы, которые лишь считывают данные из поля класса, имеет смысл делать константными, поскольку у них нет необходимости изменять значения полей объектов класса.

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

Пример класса Distance

Для того чтобы не включать множество нововведений в одну программу, мы до сих пор не использовали в наших примерах константные методы. Однако существует немалое количество ситуаций, где применение константных методов было бы весьма полезным. Например, метод showdist() класса Distance, неоднократно фигурировавшего в наших примерах, следовало сделать константным, потому что он не изменяет (и не должен изменять!) полей того объекта, для которого он вызывается. Он предназначен лишь для вывода текущих значений полей на экран

...

взято из стр 250, Лафоре Р. - Объектно-ориентированное программирование в С++ (4-е изд.) 2004

Хотя, какой порядок будет в голове, если даже в книге по ООП, пишут то верно, то - не верно. Хотя, возможно, дело в переводе.
 
Alexey Kozitsyn:

Дмитрий, Вы понимаете, что если так говорить, у тех, кто впервые начнет знакомиться с ООП вот с такой терминологией крыша поедет!? 

Это Вам, возможно, очевидно. Я вот читаю и думаю, как член _х может принадлежать классу, если класс - это инструкция, абстракция, как Вы сами сказали:

Вы серьезно не понимаете различий между классом и экземпляром класса!? Нельзя так говорить, ни в коем случае, потому что это у читающего вызовет взрыв мозга, и он подумает, что объект который вызвал метод и объект obj - это экземпляры разных классов, хотя они экземпляры одного класса (в приведенном Вами примере). 

Терминология тогда "немного того", когда не понимаешь с чем имеешь дело. Нужно просто ясно понимать что такое класс (инструкция), а что такое объект (экземпляр) класса. И тогда множество проблем отпадут сами собой. Видимо переубедить мне Вас не получится, так что дальше на эту тему дискутировать смысла не вижу. Очень жаль.

Зачем вам меня переубеждать? В чем именно переубеждать? У меня все нормально. Мне для полного бесконфликтного понимания было достаточно первого поста данной темы.

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

ps. Не надо мне приписывать кучу своих собственных заблуждений.

 
George Merts:

Лично я всегда понимал const-методы, как методы, которые не могут менять переменные класса.

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

Static-методы использую широко и густо. Практически в любом сколь-нибудь сложном классе. Обычно это "обслуживающие" дополнительные методы, для работы которых не нужно обращение к переменным класса.

Кроме того, для констант типа "количество секунд в сутках" стараюсь использовать конструкцию static const, а не #define. При этом объявление и инициализация такой константы находится в разных местах, но зато, происходит контроль типов, который также меня не раз выручал.

То же самое - редко использую. Собственно, я и тему-то завел от того, что один из участников этого форума меня спросил в личке, зачем они нужны.
 
George Merts:

Лично я всегда понимал const-методы, как методы, которые не могут менять переменные класса.

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

Вы по этой причине их НЕ используете, а я именно по этой причине их ИСПОЛЬЗУЮ:

zaskok3:

Для меня использование const и static очень сильно повышает читабельность/понимание собственного кода. И позволяет часто отловить баг или изъяны в собственной архитектуре на ранних этапах ее реализации.


Все пишу только для себя. И казалось бы, ну не буду все равно менять какие-то данные, которые не следовало бы. Но желание защититься от собственной дурости заставляет клепать ООП-архитектуру так, чтобы было доступно к измению только то, что должно быть доступно. Остальное - нет. И тут const + виды наследования очень выручают. Рекомендую.
 

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

Вот такие ошибки выдает при компиляции  'delete' - name expected

красным выделена ошибка в коде

void delete(int type){

   if(OrdersTotal()>0){

      for(i=OrdersTotal()-1;i>=0;i--){

         OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

         if(type!=6 && type!=7 && type!=8)if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic && OrderType()==type)OrderDelete(OrderTicket());

         if(type==6)if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic && OrderType()==OP_BUYSTOP || OrderType()==OP_SELLSTOP || OrderType()==OP_BUYLIMIT || OrderType()==OP_SELLLIMIT)OrderDelete(OrderTicket());

         if(type==7)if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic && OrderType()==OP_BUYSTOP || OrderType()==OP_BUYLIMIT)OrderDelete(OrderTicket());

         if(type==8)if(OrderSymbol()==Symbol() && OrderMagicNumber()==magic && OrderType()==OP_SELLSTOP || OrderType()==OP_SELLLIMIT)OrderDelete(OrderTicket());

      }

   }


Вот еще ошибка '(' - object pointer expected

   if(oppositedelete){delete(OP_SELLSTOP);delete(OP_SELLLIMIT);}

И вот здесь  '}' - not all control paths return a value

int countglobal(){

   int cnt=0;

   if(OrdersTotal()>0){

      for(i=OrdersTotal()-1;i>=0;i--){

         OrderSelect(i,SELECT_BY_POS,MODE_TRADES);

         cnt++;

      }

      return(cnt);

   }

}  

 
zaskok3:

Вы по этой причине их НЕ используете, а я именно по этой причине их ИСПОЛЬЗУЮ:

Согласен, что спецификатор const полезен при чтении и понимании давно написанных функций. А вот ограничение доступа к переменным, как мне кажется, более разумно осуществлять с помощью объявления их в разных секциях private-protected-public (лично я никогда не объявляю переменные как public, только методы).

Мне сложно придумать ситуацию, когда бы внутренняя переменная класса не должна была бы модифицироваться в потомках.

 
Anton Razmyslov:

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

А в логике ? Зачем захламлять подобными вопросами совсем непрофильную тему ?
 

Кстати никто не написал, что модификатор Const не только не позволяет изменять данные внутри собственного класса, но и даже обращаться к неконстантным методам. Простой пример: есть класс позиции, необходимо отсортировать список позиций по прибыли. Прибыль рассчитывается по запросу:

class CPosition : public CObject
{
private:
   double m_profit;
   void CalculateProfit()
   {
      m_profit = 31337;
   }
public:
   CPosition(void) : m_profit(0.0)
   {
   }
   double Profit(void)const
   {
      if(m_profit == 0.0)
         CalculateProfit(); // <- Константный метод вызывает блок рассчета и вызывает ошибку
      return m_profit;
   }
   virtual int Compare(const CObject *node,const int mode=0) const
   {
      const CPosition* pos = node;
      if(pos.Profit() > Profit())
         return 1;
      else if(pos.Profit() < Profit())
         return -1;
      return 0;
   }
};

Данный код вызовет ошибку, потому что хотя метод Profit и является константным, он если прибыль еще не рассчитана, обращается к неконстантому методу CalcultaeProfit.

Замечу, что сам метод Profit абсолютно безопасен: он гарантирует что возвращаемое им значение не будет пустым. Однако константный метод требует отказаться от расчетов за кулисами и высокой безопасности кода в пользу каких-то из пальца высосанных конструкций, которые не понятно что и зачем ограничивают.

Причина обращения: