Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 56, средняя оценка - 4.66
Roof
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
#1

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

08.08.2011, 21:09. Просмотров 7347. Ответов 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
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.08.2011, 21:09
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Константные функции-члены класса, возвращающие ссылку на константу (C++):

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

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

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

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

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

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

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Сыроежка
Заблокирован
09.08.2011, 01:25 #16
Цитата Сообщение от PointsEqual Посмотреть сообщение
Maxwe11, если ссылка утерена, об этом можно у Мэйерса почитать (28 правило, 55сов.)
Забавный случай. Вы не правильно поняли Майерса и, делая неправильные рекомендации, при этом ссылаетесь на Майерса. Приведенный вами пример, якобы, демонстрирующий ваше утверждение, как раз демонстрирует противоположное вашему утверждение. То есть приведенный вами пример корректно работае и не является подтверждением вашего утверждения.

Так что вам еще раз придется перечитать Майерса..

Добавлено через 4 минуты
Цитата Сообщение от Roof Посмотреть сообщение
2 PointsEqual
1) Т.е., насколько я понимаю - в методах моего класса нужно вернуть объект типа string, а не ссылку на константу?
2) Желаю разобраться, что же в этом примере "плохого".
Я его понимаю так - sss присваивается значение, возвращаемое методом get_name(), а этот метод вызвал временный объект типа person. Т.е. объект исчез, а ссылка так и осталась висеть в памяти? Если бы метод get_name() возвращал объект типа string, то этот возвращаемый объект исчезнет вместе с временным объектом типа person?
C++
1
2
3
4
string str1 = "Alexander";
string str2 = "Zelenogradsk";
string sss = ( person( str1, str2 ).get_name() );
cout << sss << endl; //выводит Alexander
Я правильно понял?
Нет, вы все правильно делали. Просто данный советчик еще сам плавает в понимании С++.
1
Roof
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 02:50  [ТС] #17
2 Сыроежка - спасибо за комментарий.
Желаю разобраться в этом вопросе досконально, потому буду ждать еще комментарии форумчан.
0
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
09.08.2011, 13:43 #18
C++
1
string sss = ( person( str1, str2 ).get_name() );
Тогда уж
C++
1
const string & sss = ( person( str1, str2 ).get_name() );
0
Roof
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 16:10  [ТС] #19
2 Deviaphan - а почему это будет лучше? Или правильней? По-моему это лишь другой вариант, ничем не лучше первого.
Хочу обоснование.
0
Deviaphan
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
09.08.2011, 17:38 #20
Цитата Сообщение от Roof Посмотреть сообщение
Хочу обоснование.
Я не говорю, что лучше. Я продемонстрировал реальное появление ошибки. Последующее использование sss приведёт к ошибке.
2
Roof
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 18:51  [ТС] #21
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
Делаю внезапно и красиво
Эксперт C++
1287 / 1221 / 50
Регистрация: 22.03.2011
Сообщений: 3,744
09.08.2011, 18:59 #22
Цитата Сообщение от Roof Посмотреть сообщение
я правильно понял твою демонстрацию?
Правильно.
Но я предпочитаю возвращать константную ссылку для сложных объектов (в том числе и строк), но не использую потенциально опасные конструкции (как в примере). Объекты, локальные для строки кода нужно использовать очень аккуратно и лучше вообще их не использовать, пока не поймёшь до конца принцип их работы и время жизни этих объектов.

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

Не по теме:

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

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

Однозначного ответа, как я понимаю тут нет.
Из всего сказанного я сделал такие выводы:
- можно возвращать константную ссылку на объект, надеясь на то, что пользователь моего класса не будет писать подобные инструкции:
C++
1
const string & sss = ( person( str1, str2 ).get_name() );
- можно возвращать сам объект, пренебрегая копированием, но не боясь приведенных выше ошибок.
0
easybudda
Модератор
Эксперт CЭксперт С++
9622 / 5570 / 946
Регистрация: 25.07.2009
Сообщений: 10,695
09.08.2011, 23:11 #25
Roof, однозначно PointsEqual правильно говорит. Ссылка действительно может пережить свой объект. Так, что, возвращайте строку, а не ссылку.
2
alex_x_x
бжни
2447 / 1652 / 84
Регистрация: 14.05.2009
Сообщений: 7,162
09.08.2011, 23:29 #26
кроме того к вопросу о копировании - в продвинутых библиотеках (в Qt точно знаю, полагаю, что так сделано и в многих реализациях stl) контейнеры реализуют идиому "письмо - конверт" (манипулятор/тело), обеспечивающую эффективные операции копирования - фактически применение принципа копирования при записи
это я к тому, что зная, что операции копирования контейнеров растратные, нужно учитывать, что они могут быть много хитрее и на самом деле не приводить к выделению памяти и копированию данных
и не пренебрегать безопасностью
2
Roof
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
09.08.2011, 23:59  [ТС] #27
easybudda, alex_x_x - спасибо за ответы, очень помогли.
0
easybudda
Модератор
Эксперт CЭксперт С++
9622 / 5570 / 946
Регистрация: 25.07.2009
Сообщений: 10,695
10.08.2011, 00:30 #28
На самом деле всё хитрее...
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
154 / 154 / 10
Регистрация: 03.11.2010
Сообщений: 393
10.08.2011, 06:27  [ТС] #29
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
easybudda
Модератор
Эксперт CЭксперт С++
9622 / 5570 / 946
Регистрация: 25.07.2009
Сообщений: 10,695
10.08.2011, 09:54 #30
Цитата Сообщение от Roof Посмотреть сообщение
А возвращать string или const string, насколько я понял нет никакой разницы.
В С функции не должны возвращать константные значения. На счёт С++ не знаю, но в принципе как-то не за чем... К примеру, если есть фукнция, переводящая строку в верхний регистр, то вот такая конструкция с константной строкой скорее всего не будет работать
C++
1
std::cout << stringToUppercase(some_person.get_name()) << std::endl;
1
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
10.08.2011, 09:54
Привет! Вот еще темы с ответами:

Константные указатели и указатели на константу - C++
Чем они, собственно говоря, отличаются? Поясните, пожалуйста. Не знаю, как так получилось, что в разных источниках - разные...

В каких случаях компилятор делает функции-члены класса встроенными (inline)? - C++
Добрый день! Хочу спросить следующее: в интернете пишут, что если делать реализацию методов класса внутри его объявления, то такие методы...

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

Константные статические объекты класса. - C++
Здравствуйте. Есть класс &quot;матрица&quot; нужно задать константные матрицы такие как E - единичная матрица и т.д., как это сделать? #include...


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

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
10.08.2011, 09:54
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru