С Новым годом! Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.66/29: Рейтинг темы: голосов - 29, средняя оценка - 4.66
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
1

Константные методы

19.08.2020, 09:04. Показов 5975. Ответов 20

Author24 — интернет-сервис помощи студентам
Здравствуйте.
Потихоньку изучаю С++. Разобрался в идее константных методов?! Они нужны для того, чтобы константный объект мог эти методы вызывать?
Но тогда почему работает такой код?

Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MyClass
{
    int* arr;
public:
    MyClass() : arr{ new int[8] } {}
    ~MyClass() { delete[] arr; }
 
    int* get() const { return arr; }
};
 
int main()
{
 
    MyClass m;
 
    int* arr = m.get();
    arr[0] = 11;
 
}


почему метод get мб константным? Вернув указатель, я могу разыменовывать его, и тем самым изменить состояние объекта? Почему такой код компилируется?
Такой код у меня не компилируется.
Кликните здесь для просмотра всего текста

C++
1
2
3
4
       MyClass const const_m;
 
    int* const_arr = const_m.get();
    const_m[0] = 11;


К чему я всё это веду? Ковыряя умные указатели, я обнаружил что метод get() класса std::unique_ptr константный. Зачем это было сделано? В чём смысл?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
19.08.2020, 09:04
Ответы с готовыми решениями:

Константные поля и методы
А можете объяснить, что такое константные поля и методы в классах?

Константные методы и объекты класса
Это необходимость, или явная подстраховка того, что бы объект (константный) работал с себе...

Дублирование кода и константные методы
Есть метод method возвращающий ссылку на внутреннее значение объекта. Существует в двух вариантах -...

Константные методы в абстрактных классах
Добрый день! Помогите, пожалуйста, разобраться с константными методами в абстрактных классах....

20
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 09:16 2
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Они нужны для того, чтобы константный объект мог эти методы вызывать?
Да. Они нужны для того, чтобы эти методы можно было вызывать в т.ч. через константный объект.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
почему метод get мб константным?
Ым... Вы же сами сказали: чтобы константный объект мог эти методы вызывать.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Вернув указатель, я могу разыменовывать его, и тем самым изменить состояние объекта?
А кто вам сказал, что массив arr является частью "состояния объекта"? Это может быть совершенно посторонний массив. Ваш объект просто хранит указатель на этот совершенно посторонний массив зачем-то (кто его знает, зачем), но массив не является частью "состояния объекта".

Так эту ситуацию видит язык С++. Язык С++ не знает, что вы лично хотели реализовать. Язык С++ не знает, является ли массив arr частью "состояния объекта" или не является.

Если вы хотите, чтобы массив arr являлся частью "состояния объекта", то эта ваша обязанность, обеспечить правильную делегацию константности, т.е. сделать так, чтобы этот массив нельзя было модифицировать для константных объектов. Это ваша обязанность возвращать именно const int * из такого константного метода. Тут все в ваших руках: как напишете, так и будет.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Такой код у меня не компилируется.

C++
1
2
3
4
    MyClass const const_m;
 
    int* const_arr = const_m.get();
    const_m[0] = 11;
А что это за белиберда вообще? Что такое const_m[0]? Разумеется, это не будет компилироваться. Но не ясно, как это относится к теме.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Ковыряя умные указатели, я обнаружил что метод get() класса std::unique_ptr константный. Зачем это было сделано? В чём смысл?
В том что модификация самого указателя и модификация указуемых данных - это совершенно разные, никак не связанные друг с другом вещи. Константность указателя означает, что нельзя модифицировать сам указатель, но совсем не означает что нельзя модифицировать указуемые данные.

Константность метода get означает только то, что он не модифицирует сам умный указатель. Благодаря этому вы можете вызывать get для константных указателей. В этом и заключается смысл.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 09:18  [ТС] 3
TheCalligrapher, спасибо за ответ.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В том что модификация самого указателя и модификация указуемых данных - это совершенно разные, никак не связанные друг с другом вещи. Константность указателя означает, что нельзя модифицировать сам указатель, но совсем не означает что нельзя модифицировать указуемые данные.
Сигнатура метода get(), наверное, такая?
C++
1
T* get() const noexcept
Если мы хотим чтобы указатель был константным, то наверное сигнатура должны быть такой?

C++
1
T* const get() const noexcept
Получается вы неправы?

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
А что это за белиберда вообще? Что такое const_m[0]? Разумеется, это не будет компилироваться. Но не явно, как это относиться к теме.
Ошибся. Извините.
Вот так у меня компилируется и работает.

Кликните здесь для просмотра всего текста

C++
1
2
3
4
MyClass const const_m;
 
int* const_arr = const_m.get();
const_arr[0] = 11;
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 09:23 4
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Если мы хотим чтобы указатель был константным
Я говорю именно о константности самого "умного указателя", а не константности возвращаемого значения get.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
то наверное сигнатура должны быть такой?

C++
1
T* const get() const noexcept
Нет, конечно. Это бессмыслица какая-то. Константность верхнего уровня для возвращаемого значения функции, когда это возвращаемое значение имеет скалярный тип (напр. обычный указатель) - это бессмыслица, которая ничего не дает вообще. (Эта константность влияет на тип функции, но более никакого практического смысла не имеет.)

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Получается вы неправы?
Нет, не получается.
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 09:27  [ТС] 5
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет, конечно. Это бессмыслица какая-то.
Я хотел выразить идею, что указатель константный. Что нельзя заставить его ссылать на другую память? Разве это не так делается?

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Я говорю именно о константности самого "умного указателя"
Что даёт константность умного указателя? Зачем это мб нужно?
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 09:33 6
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Вот так у меня компилируется и работает.

C++
1
2
3
4
MyClass const const_m;
 
int* const_arr = const_m.get();
const_arr[0] = 11;
Это нормально. Ваша реализация MyClass фактически говорит о том, что массив arr внутри MyClass НЕ является частью состояния MyClass. Соответственно, константность MyClass НЕ распространяется на массив arr.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Я хотел выразить идею, что указатель константный. Что нельзя заставить его ссылать на другую память? Разве это не так делается?
"Заставить ссылаться на другую память" можно только переменную типа указатель, то есть изменяемое lvalue. Скалярный результат работы функции get - это не переменная, это просто эфемерное значение, rvalue. Его невозможно поменять в принципе. К нем вообще неприменимо понятие "поменять". Поэтому и навешивать на него const верхнего уровня нет никакого смысла.

Например, результат выражения 2+3 имеет тип int. Обратите внимание: int, а не const int. Это, однако, не значит, что вы можете каким-то образом "поменять" результат выражения 2+3. То же самое относится и к результату метода get: вы не можете его поменять, независимо от того, есть на нам const или нет.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Что даёт константность умного указателя? Зачем это мб нужно?
Как это "зачем"? Допустим вы хотите, чтобы этот указатель всегда указывал в одно и то же место. Т.е чтобы такой указатель никто не мог поменять (т.е. перенаправить в другое место). Вот для этого вы и делаете его константным.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 09:40  [ТС] 7
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Как это "зачем"? Допустим вы хотите, чтобы этот указатель всегда указывал в одно и то же место. Т.е чтобы такой указатель никто не мог поменять (т.е. перенаправить в другое место). Вот для этого вы и делаете его константным.
Но я и так не могу его поменять?

Вот мой простой класс.
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
class MyClass
{
    int* arr;
public:
    MyClass() : arr{ new int[8] } {}
    ~MyClass() { delete[] arr; }
 
    int* get() const { return arr; }
};


Вот его использование.

Кликните здесь для просмотра всего текста

C++
1
2
3
4
int* new_arr = new int[16];
 
MyClass m;
m.get() = new_arr;


Я ведь не могу сделать так? У меня не будет компилироваться? Аналогично, и с unique_ptr. Я никак не могу заставить его ссылать на другую область памяти. И константным его делать мне не нужно. Следовательно, делать константным метод get тоже.
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 09:52 8
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Но я и так не могу его поменять?
Как это "не можете"? У стандартных умных указателей есть модифицирующие методы, которые их меняют, т.е. перенаправляют в новое место. Например, у std::unique_ptr есть метод reset. И оператор присваивания у него тоже есть. И метод swap.

Разумеется, все эти методы - неконстантны. То есть вызвать их для константного std::unique_ptr вы не сможете.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Я ведь не могу сделать так?
Для вашего класса? Да, именно так вы сделать не сможете. А вот так - сможете

C++
1
2
MyClass a, b;
a = b;
В результате содержимое a изменится (с катастрофическими последствиями). Если бы a был const, то выполнить такое присваивание вы бы не смогли.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 10:10  [ТС] 9
TheCalligrapher, спасибо. Я разобрался.

Добавлено через 11 минут
TheCalligrapher, получается, что в моё случае, правильная реализация идеи константности, заключается в ведение метода get_const(). Тем самым я говорю, что указатель arr - это моё состояние?!
Кликните здесь для просмотра всего текста

C++
1
2
3
4
5
6
7
8
9
10
class MyClass
{
    int* arr;
public:
    MyClass() : arr{ new int[8] } {}
    ~MyClass() { delete[] arr; }
 
    int* get()  { return arr; }
    int const* get_const() const { return arr; }
};


А метод get, в таком случае можно сделать не константным?!
0
19409 / 10028 / 2443
Регистрация: 30.01.2014
Сообщений: 17,678
19.08.2020, 10:13 10
schoolboy_, у вас может быть два метода get, один константный, другой - нет.

C++
1
2
3
4
5
6
7
8
9
10
class MyClass
{
    int* arr;
public:
    MyClass() : arr{ new int[8] } {}
    ~MyClass() { delete[] arr; }
 
    int* get()  { return arr; }
    int const* get() const { return arr; }
};
Первый get вы не сможете вызвать на константном объекте MyClass, а второй - сможете.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 10:15  [ТС] 11
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Как это "не можете"? У стандартных умных указателей есть модифицирующие методы, которые их меняют, т.е. перенаправляют в новое место. Например, у std::unique_ptr есть метод reset. И оператор присваивания у него тоже есть
Погодите. Такого быть не может? Если есть оператор присваивания, то вся идея уникального указателя пропадает? Есть Есть перемещающий оператор присваивания? Вы его имели в виду?
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 10:16 12
Цитата Сообщение от schoolboy_ Посмотреть сообщение
равильная реализация идеи константности, заключается в ведение метода get_const(). Тем самым я говорю, что указатель arr - это моё состояние?!
Зачем? То есть можно так, но элегантнее будет просто применить перегрузку функций, т.е. сделать так, как показал DrOffset.
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 10:20  [ТС] 13
Цитата Сообщение от DrOffset Посмотреть сообщение
schoolboy_, у вас может быть два метода get, один константный, другой - нет.
вы предлагает сделать так?

C++
1
2
 int* get()  { return arr; }
 int* get() const {return arr;}
Но в чём смысл. Да, я смогу вызвать константный метод на константном объекте. Но идея константности теряется, потому что я могу менять состояние массива. Я же хочу выразить идею, что данный указатель - состояние моего объекта.
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 10:24 14
Лучший ответ Сообщение было отмечено schoolboy_ как решение

Решение

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Погодите. Такого быть не может? Если есть оператор присваивания, то вся идея уникального указателя пропадает? Есть Есть перемещающий оператор присваивания? Вы его имели в виду?
Если ваш указатель должен быть уникальным, то это ваша задача - реализовать эту уникальность так, как вы ее себе представляете. Либо запретить присваивание вообще, либо сделать его перемещающим (как в std::unique_ptr), либо еще как-то...

Вы же сами сказали, что у вас содержимое arr является частью состояния MyClass. Ну так тогда, наверное, правильнее будет сделать оператор присваивания, который будет копировать не указатель, а именно содержимое arr?

В любом случае: все определяется вашим замыслом. Что вы реализуете, то и получится в результате. Все в ваших руках.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
вы предлагает сделать так?
Посмотрите внимательнее, что написано в коде у DrOffset. Там не так.

Цитата Сообщение от schoolboy_ Посмотреть сообщение
Я же хочу выразить идею, что данный указатель - состояние моего объекта.
Не понял. Что именно является частью состояния? Только сам указатель? Или и указуемые данные тоже?
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 10:24  [ТС] 15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если ваш указатель должен быть уникальным, то это ваша задача - реализовать эту уникальность так, как вы ее себе представляете
Понятно. Никто ведь не может помешать мне написать такой код:

C++
1
2
std::unique_ptr<MyClass> p(new MyClass());
std::unique_ptr<MyClass> copy_p(p.get());
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Посмотрите внимательнее, что написано в коде у DrOffset. Там не так.
Да. Я был не прав. DrOffset, вопрос снимается.
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 10:26 16
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Понятно. Никто ведь не может помешать мне написать такой код:

C++
1
2
std::unique_ptr<MyClass> p(new MyClass());
std::unique_ptr<MyClass> copy_p(p.get());
Ну здесь уж вы "сам себе злобный Буратина".
0
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 10:34  [ТС] 17
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Не понял. Что именно является частью состояния? Только сам указатель?
Указатель всегда является частью состояния? Я не могу его никак изменить при такой реализации. А если я хочу чтобы константный объект не мог менять ещё и данные, то я должен сделать так, как написал DrOffset?
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 10:39 18
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Указатель всегда является частью состояния? Я не могу его никак изменить при такой реализации.
Да, сам указатель arr всегда является частью состояния MyClass. Если весь объект MyClass константен, то и указатель arr константен. Поменять сам указатель в такой ситуации вы не можете ни при какой реализации. (Кроме случая, когда вы сами объявили этот указатель как mutable)

Цитата Сообщение от schoolboy_ Посмотреть сообщение
А если я хочу чтобы константный объект не мог менять ещё и данные, то я должен сделать так, как написал DrOffset?
Именно так. "По умолчанию" константность MyClass не распространяется на указуемые данные. Распространить константность MyClass на указуемые данные можно только аккуратной реализацией такого "распространения" вручную. Например так, как показал DrOffset.
1
3 / 3 / 1
Регистрация: 02.03.2013
Сообщений: 231
19.08.2020, 11:06  [ТС] 19
Ещё такой вопрос. Я добавил в свой класс две функции
C++
1
2
    int& get(int offset) {return arr[offset]};
    int const & get(int offset) const  {return arr[offset]};
Я понимаю, что если я сделаю так:
C++
1
m.get(0) = 11
то вызовется не константная функция. Константная вызовется только на константном объекте? Другого способа сказать, что нужно вызвать константную функцию нет?
0
Вездепух
Эксперт CЭксперт С++
12792 / 6669 / 1795
Регистрация: 18.10.2014
Сообщений: 16,877
19.08.2020, 11:09 20
Цитата Сообщение от schoolboy_ Посмотреть сообщение
Другого способа сказать, что нужно вызвать константную функцию нет?
Можно так

C++
1
2
const MyClass &cm = m;
cm.get(0);
или просто

C++
1
const_cast<const MyClass &>(m).get(0);
и вызовется константная версия метода. Считать ли это "другим способом" - вопрос отдельный...

В данном случае объект m неконстантен, но вы как бы создаете константный "пусть доступа" к нему - ссылку (или указатель). И уже через этот "пусть доступа" вызываете константный метод. Менее громоздких способов нет.
1
19.08.2020, 11:09
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
19.08.2020, 11:09
Помогаю со студенческими работами здесь

Константные и неконстантные методы в классе
Здравствуйте! Вот задача https://stepik.org/lesson/563/step/6?unit=886 Я наверное не очень...

Константные и не константные ссылки. Приведения типов. Нужно уточнение
Не очень понимаю в чем различие (2,3 строчки). int x = 10; double &amp;y = x; const double &amp;y...

Константные объекты
#include &lt;iostream&gt; #include &lt;windows.h&gt; using namespace std; class CTest { public: int...

Константные функции
Почему все работает? class My { public: My(); int retFunc() const; private: ...

Константные функции-члены
можно ли функцию-член объявить константной, если она возвращает указатель-член класса? Ведь она не...

Константные поля класса
Такой вопрос, как инициализировать константные поля класса? Работают конструкции вида obj():t(0){};...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru