Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.84/58: Рейтинг темы: голосов - 58, средняя оценка - 4.84
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393

Константные функции-члены класса, возвращающие ссылку на константу

08.08.2011, 21:09. Показов 13329. Ответов 64
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Упражняюсь по книге Липпмана, выполняю задания по теме классы.
Необходимо реализовать класс person, который способен хранить имя и адрес человека, а также создать функции, возвращающие при обращении имя и адрес.
Вопрос, который ставит автор книги: "Должны ли эти функции быть константными? Объясните почему."
Вот тут я начал путаться. Вот моя реализация:
файл person.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef PERSON_H_
#define PERSON_H_
 
class person {
public:
    //конструктор, принимающий две строки типа string
    person( std::string &_name, std::string &_addres ) :
        name( _name ), addres( _addres ) {
    }
    //метод, возвращающий addres
    const std::string &get_addres() const {
        return addres;
    }
    //метод, возвращающий name
    const std::string &get_name() const {
        return name;
    }
 
private:
    //поле для хранения имени
    std::string name;
    //поле для хранения адреса
    std::string addres;
};
 
#endif /* PERSON_H_ */
Для тестирования класса, файл test_class_person.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "person.h"
using namespace std;
 
int main() {
    string str1 = "Alexander";
    string str2 = "Zelenogradsk";
    person pers( str1, str2 );
    cout << pers.get_name() << " " << pers.get_addres() << endl;
    
    string str3 = pers.get_name();
    str3 += "222";
    cout << str3 << " " << pers.get_name();
    return 0;
}
Я решил так
1) Константными эти функции должны быть, так как они не меняют значений переменных-членов объекта.
2) Возвращать они должны лишь константную ссылку на строку, а не просто тип string, дабы избежать ненужного копирования.
Прав ли я? Если нет, то объясните почему.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
08.08.2011, 21:09
Ответы с готовыми решениями:

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

Константные функции-члены ?
Для чего использовать #define ? не имеют права изменять поля класса почему ? class Array { ... inline double operator...

класс «Строка» (данные-члены класса – строчка, функции-члены класса – операции)
Помогите пожалйуста с реализацией программы... Реализовать класс «Строка» (данные-члены класса – строчка (указатель на массив, ...

64
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 18:51  [ТС]
Студворк — интернет-сервис помощи студентам
2 Deviaphan - Спасибо за демонстрацию, повторное использование действительно невозможно и сделать &sss ссылкой на не константную переменную тоже невозможно.

Если изменить методы класса person так:

C++
1
2
3
4
5
6
7
8
9
10
...
//метод, возвращающий addres
    std::string get_addres() const {
        return addres;
    }
    //метод, возвращающий name
    std::string get_name() const {
        return name;
    }
...
То такие варианты использования уже невозможны:
C++
1
const string &sss = ( person( str1, str2 ).get_name() );
C++
1
string &sss = ( person( str1, str2 ).get_name() );
А вот такие варианты уже возможны:
C++
1
const string sss = ( person( str1, str2 ).get_name() );
C++
1
2
string sss = ( person( str1, str2 ).get_name() );
sss += str2;
Насколько я понял, вариант, когда методы класса возвращают не ссылку, а объект - предпочтителен, так как более защищен от возникновения ошибок. Deviaphan, я правильно понял твою демонстрацию?
0
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
09.08.2011, 18:59
Цитата Сообщение от Roof Посмотреть сообщение
я правильно понял твою демонстрацию?
Правильно.
Но я предпочитаю возвращать константную ссылку для сложных объектов (в том числе и строк), но не использую потенциально опасные конструкции (как в примере). Объекты, локальные для строки кода нужно использовать очень аккуратно и лучше вообще их не использовать, пока не поймёшь до конца принцип их работы и время жизни этих объектов.

Т.е. лучше возвращать константную ссылку, но использовать код вида:
C++
1
2
Person temp( str1, str2 );
const string &sss = temp.get_name();
1
ниначмуроФ
 Аватар для PointsEqual
851 / 535 / 110
Регистрация: 12.10.2009
Сообщений: 1,913
09.08.2011, 19:26
Цитата Сообщение от Roof Посмотреть сообщение
Насколько я понял, вариант, когда методы класса возвращают не ссылку, а объект - предпочтителен

Не по теме:

наконет-то свершилось

0
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 22:01  [ТС]
Цитата Сообщение от Deviaphan Посмотреть сообщение
Но я предпочитаю возвращать константную ссылку для сложных объектов (в том числе и строк)
Вот и я думаю, что константную ссылку на объект возвращать продуктивней, дабы избежать копирования. Но опять же, PointsEqual рекомендует возвращать сам объект, дабы избежать возможности возникновения указанных выше ошибок, которые могут возникнуть при использовании моего класса.

Однозначного ответа, как я понимаю тут нет.
Из всего сказанного я сделал такие выводы:
- можно возвращать константную ссылку на объект, надеясь на то, что пользователь моего класса не будет писать подобные инструкции:
C++
1
const string & sss = ( person( str1, str2 ).get_name() );
- можно возвращать сам объект, пренебрегая копированием, но не боясь приведенных выше ошибок.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
09.08.2011, 23:11
Roof, однозначно PointsEqual правильно говорит. Ссылка действительно может пережить свой объект. Так, что, возвращайте строку, а не ссылку.
2
бжни
 Аватар для alex_x_x
2473 / 1684 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
09.08.2011, 23:29
кроме того к вопросу о копировании - в продвинутых библиотеках (в Qt точно знаю, полагаю, что так сделано и в многих реализациях stl) контейнеры реализуют идиому "письмо - конверт" (манипулятор/тело), обеспечивающую эффективные операции копирования - фактически применение принципа копирования при записи
это я к тому, что зная, что операции копирования контейнеров растратные, нужно учитывать, что они могут быть много хитрее и на самом деле не приводить к выделению памяти и копированию данных
и не пренебрегать безопасностью
2
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 23:59  [ТС]
easybudda, alex_x_x - спасибо за ответы, очень помогли.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
10.08.2011, 00:30
На самом деле всё хитрее...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
#include <string>
 
class person {
public:
        //конструктор, принимающий две строки типа string
        person( const std::string &_name, const std::string &_address ) :
                name( _name ), address( _address ) {
        }
        //метод, возвращающий addres
        const std::string &get_address() const {
                return address;
        }
        //метод, возвращающий name
        const std::string &get_name() const {
                return name;
        }
        void set_name(const std::string & _name) { 
            name = _name; 
        }
        void set_address(const std::string & _address) { 
            address = _address; 
        }
 
private:
        //поле для хранения имени
        std::string name;
        //поле для хранения адреса
        std::string address;
};
 
int main(){
    person p("Vasya", "Hell");
    
    const char * n = p.get_name().c_str();
    std::cout << n << std::endl;
    p.set_name("Petya");
    std::cout << n << std::endl;
    
    return 0;
}
Два раза выведет Васю. Думаю, функции get_name, get_address (кстати, это слово с двумя s пишется) на самом деле создают константные копии строк, ссылки на которые и возвращают. Сэкономить в любом случае не получится, морока одна. Возвращайте строки.
2
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
10.08.2011, 06:27  [ТС]
2 easybudda,
Цитата Сообщение от easybudda Посмотреть сообщение
Думаю, функции get_name, get_address (кстати, это слово с двумя s пишется) на самом деле создают константные копии строк, ссылки на которые и возвращают. Сэкономить в любом случае не получится, морока одна. Возвращайте строки.
Об этом не догадывался, большое спасибо за информацию.
Однозначно - буду возвращать строку, а не ссылку.

Но мне не понятен смысл Вашего примера. Вот как я его понял:
Методы get_name() и get_address() возвращают ссылку на константу, как в Вашем примере.
C++
1
2
3
4
5
6
7
8
...
person p("Vasya", "Hell");
 
const char * n = p.get_name().c_str();  //строка n в стиле C инициализирована строкой "Vasya"
std::cout << n << std::endl; //вывели n
p.set_name("Petya");    //никакого отношения к n не имеет
std::cout << n << std::endl; //снова вывели n
...
В Вашем примере выводится два раза Vasya. Как я понимаю - это логично, ведь n инициализирована вначале, потом хоть сколько меняй состояние объекта p - на n это никак не отразится.

Также два раза выведется Vasya, если методы get_name() и get_address() будут возвращать константные строки или просто строки. Соответственно объявление и инициализацию переменной n я проводил так:
C++
1
const std::string n = p.get_name();
или
C++
1
std::string n = p.get_name();
А возвращать string или const string, насколько я понял нет никакой разницы.

Т.е. осталось понять, что именно Вы хотели сказать в Вашем примере.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
10.08.2011, 09:54
Цитата Сообщение от Roof Посмотреть сообщение
А возвращать string или const string, насколько я понял нет никакой разницы.
В С функции не должны возвращать константные значения. На счёт С++ не знаю, но в принципе как-то не за чем... К примеру, если есть фукнция, переводящая строку в верхний регистр, то вот такая конструкция с константной строкой скорее всего не будет работать
C++
1
std::cout << stringToUppercase(some_person.get_name()) << std::endl;
1
Эксперт С++
 Аватар для CyBOSSeR
2348 / 1721 / 149
Регистрация: 06.03.2009
Сообщений: 3,675
10.08.2011, 10:30
Цитата Сообщение от Deviaphan Посмотреть сообщение
Но я предпочитаю возвращать константную ссылку для сложных объектов
В таких случаях умные указатели предпочтительнее, возвращать ссылки - слишком потенциально опасное действие, чтобы его производить.
1
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
10.08.2011, 10:40
умные указатели предпочтительнее
Абсолютно да!
Но чтобы возвращать умные указатели на внутренние данные объекта, эти данные должны быть умными указателями. Что не всегда желательно и возможно.
С другой стороны, С++ вообще очень потенциально опасный язык и речь должна идти о культуре программирования и опыте программиста. Когда пишешь простой и понятный код, опасные конструкции встречаются гораздо реже.
0
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
10.08.2011, 15:22  [ТС]
Спасибо всем ответившим. На свой вопрос получил однозначный ответ.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
10.08.2011, 15:42
Roof, ну и в заключении поясню суть своего примера: я его дома на ноуте с debian делал, там, напомню, два раза Vasya вывелось. А вот, как этот же самый код (отсюда скопировал) с другими компиляторами работает:


Можно долго гадать, или разбираться, почему оно так, но лучше просто не оставлять такие вещи на откуп компилятору...
2
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
10.08.2011, 15:50
Цитата Сообщение от easybudda Посмотреть сообщение
почему оно так
Второй раз не Вася вывелся, а Вас(стрелочка).
0
53 / 53 / 8
Регистрация: 21.03.2009
Сообщений: 371
10.08.2011, 16:03
Возврат const string & необходим чтобы избежать возможности изменять private часть класса без использования интерфейса
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<iostream>
#include<string>
using namespace std;
class A {
private:
string str;
public:
    A();
    string & fun();
    void show(){
     cout<<str;
    }
};
int main() {
  A obj;
  obj.show();
  obj.fun()="kol";//изменили str
  cout<<endl;
  obj.show();
  cin.get();
  return 0;
}
A::A(){
str="gflj";
}
string & A::fun(){
return str;
}
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
10.08.2011, 16:04
Цитата Сообщение от Deviaphan Посмотреть сообщение
Второй раз не Вася вывелся, а Вас(стрелочка).
Да, я заметил. В cygwin указатель указывает на буфер строки, которая к моменту второго обращения уже не существует. Мелкомягкий каким-то чудом сохраняет указатель, хоть она к тому времени и поменялась (на сколько знаю, оператор = должен бы уничтожать старую строку и создавать новую), а вот в BSD снова два Васи и без стрелок:
1
Делаю внезапно и красиво
Эксперт С++
 Аватар для Deviaphan
1313 / 1228 / 72
Регистрация: 22.03.2011
Сообщений: 3,744
10.08.2011, 16:08
Цитата Сообщение от easybudda Посмотреть сообщение
Мелкомягкий каким-то чудом сохраняет указатель
Не исключено, что была создана копия строки, в целях оптимизации. Насколько я помню, короткие строки хранятся в массиве в самом объекте, без выделения памяти. А раз обещался const компилятор мог создать копию. Поэтому изменив оригинальный объект осталась строка в копии... А вообще, чего гадать на ошибках, лучше так не писать и усё.)
1
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
 Аватар для easybudda
12843 / 7592 / 1766
Регистрация: 25.07.2009
Сообщений: 13,981
10.08.2011, 16:25
Цитата Сообщение от Deviaphan Посмотреть сообщение
Поэтому изменив оригинальный объект осталась строка в копии...
Так в том и прикол, что мелкомягкий не создавал копии, просто вернул указатель на массив char* от строки-члена класса, который сохранился после присвоения строке другого значения, скорее всего по причине
Цитата Сообщение от Deviaphan Посмотреть сообщение
короткие строки хранятся в массиве в самом объекте, без выделения памяти
А вот про это
Цитата Сообщение от Deviaphan Посмотреть сообщение
лучше так не писать
я собственно и говорил.

Цитата Сообщение от lavan Посмотреть сообщение
Возврат const string & необходим чтобы избежать возможности изменять private часть класса без использования интерфейса
Спасибо, Кэп, разобрались уже...
0
 Аватар для Roof
155 / 155 / 44
Регистрация: 03.11.2010
Сообщений: 393
10.08.2011, 17:56  [ТС]
2 easybudda - я все примеры тестирую на Ubuntu с g++ и Ваш пример у меня вывел два раза Vasya, как и у Вас на Debain и BSD.

Цитата Сообщение от easybudda Посмотреть сообщение
Можно долго гадать, или разбираться, почему оно так, но лучше просто не оставлять такие вещи на откуп компилятору...
- с этим полностью согласен.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
10.08.2011, 17:56

Почему нехорошо себя ведёт конструктор класса (не компилится ничё), если ему параметром ссылку на константу?
То есть вообще непонятно ничё, вот, смотрите, этот пример не компилится: #include &lt;stdio.h&gt; class fee { public: //Не...

ООП - Указатели на функции члены класса
Не пойму в чем ошибка, MVS2017 при компиляции выдает целую стопку ошибок: #include &lt;iostream&gt; using namespace std ...

Массив указателей на функции-члены класса
Задача заключается в том, что в private надо создать статическую переменную символьного типа, в protected просто переменные вещественного...

Константные массивы как члены класса и ошибка Call of nonfunction
Здравствуйте. Я по двум связанным вопросам. 1) Требуется объявить константный массив как член класса. По статейки с форума rsdn (не...

Использование указателей на функции-члены внутри самого класса
День добрый форум! Возник такой вопрос. В классе А есть 3 функции и массив, в котором хранятся адреса этих функций. class A ...


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru