Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.50/6: Рейтинг темы: голосов - 6, средняя оценка - 4.50
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
#1

Возврат ссылки на закрытый элемент данных с++

21.08.2015, 01:45. Просмотров 1081. Ответов 19
Метки нет (Все метки)

Я не могу понять как устроена проблема с возвратом ссылки на закрытый элемент данных.
C++ (Qt)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Time{
public:
    int &badSetHour(int hh){
        hour = (hh >= 0 && hh < 24) ? hh : 0;
        return hour;
    };
private:
    int hour;
};
 
 
void main(){
    Time t;
    int &hourRef = t.badSetHour(20);
    hourRef = 30;
    t.badSetHour(12) = 74;
        system("pause");
 
}
Во первых что и как делает строка 3(точнее как влияет &)?
Во вторых сама тема... Как устроена проблема с возвратом ссылки на закрытый элемент данных.
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
21.08.2015, 01:45
Ответы с готовыми решениями:

Возвращение ссылки или указателя на закрытый элемент класса.
Всех уважаемых форуман. поздравляю с наступившим новым годом и прошу ответить...

Возврат ссылки
Задача которая считывает массив и определяет минимальный, макисмальный, первый...

Возврат ссылки
int &amp; function(int); Понятно для чего передают аргументы в функцию как...

Возврат ссылки из метода
Доброго времени суток! Дано: структура: struct Point { float x; float...

Возврат ссылки из функции
Изучаю С++, знаю С. Вот такой простенький вопросик есть. В чем вообще...

19
Renji
2102 / 1543 / 470
Регистрация: 05.06.2014
Сообщений: 4,466
21.08.2015, 01:59 #2
Цитата Сообщение от vasea_morozov Посмотреть сообщение
Во первых что и как делает строка 3(точнее как влияет &)?
int&link это такой int*link, только всегда разыменован (*link). В стандарте это вроде как немного другими словами, но техническая реализация ссылки 99% что будет именно через указатель.
Цитата Сообщение от vasea_morozov Посмотреть сообщение
Во вторых сама тема... Как устроена проблема с возвратом ссылки на закрытый элемент данных.
Да как-то плевать закрытый он или открытый.
0
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
21.08.2015, 02:19  [ТС] #3
Тут,получается проблема в том что Privat переменную hour можно изменить в обход проверки в 4 строке.
И я пытаюсь понять этот механизм
0
Renji
2102 / 1543 / 470
Регистрация: 05.06.2014
Сообщений: 4,466
21.08.2015, 02:30 #4
Цитата Сообщение от vasea_morozov Посмотреть сообщение
Тут,получается проблема в том что Privat переменную hour можно изменить в обход проверки в 4 строке.
И я пытаюсь понять этот механизм
А никакого механизма нет. Просто модификатор private это не более чем надпись на заборе и никакими защитными свойствами этот забор (переменную) не наделяет. Если компилятор замечает табличку "не влезай, убьет!" он на этот забор лезть отказывается. Если табличку спрятать (вернув ссылку), то полезет и ничего особенного не произойдет. Забор как забор.
2
ASCII
93 / 66 / 12
Регистрация: 15.12.2013
Сообщений: 415
Завершенные тесты: 2
21.08.2015, 02:38 #5
суть в том, что чисто технически данные, объявленные в области private являются закрытыми, что означает, что Вы не сможете напрямую получить к ним доступ, вот пример небольшой:

Напишите в main вот так:
C++
1
2
    Time t;
    t.hour = 10;
И у Вам компилятор выдаст ошибку, мол дружище, ты пытаешься получить доступ к закрытой переменной, а нельзя так. Вот и все, весь механизм private, запретить доступ к данным извне, но никто не мешает Вам вернуть ссылку или же указатель на эти данные через открытую(public) функцию и делать уже с ними что хочешь.

Другое дело, что это считается дурным тоном.
1
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
21.08.2015, 02:52  [ТС] #6
Возможно отхожу от темы...
в какой момент переменная hour принимает новое значение?
C++ (Qt)
1
2
3
int &badSetHour(int hh){
        hour = (hh >= 0 && hh < 24) ? hh : 0; // если тут то как игнорируется условия?
        return hour;
C++ (Qt)
1
2
3
4
 Time t;
    int &hourRef = t.badSetHour(20);// А тут на сколько важно &hourRef какое число будет t.badSetHour(тут)
    hourRef = 30;
    t.badSetHour(12) = 74;
да и потом, я же создал сылку на функцию а не на переменную, ведь так?
0
ASCII
93 / 66 / 12
Регистрация: 15.12.2013
Сообщений: 415
Завершенные тесты: 2
21.08.2015, 03:05 #7
Цитата Сообщение от vasea_morozov Посмотреть сообщение
да и потом, я же создал сылку на функцию а не на переменную, ведь так?
Вот тут вы заблуждаетесь, вы создали функцию, которая возвращает ссылку на тип int.

Ссылка на функцию имеет немного иной вид:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void foo()
{
    std::cout << "Hello from foo()\n";
}
 
int main(int argc, char **argv)
{
    setlocale(LC_CTYPE, ".1251");
    
    void(&lnkToFunc)() = foo;
    lnkToFunc();  // Hello from foo()
    
    std::cin.get();
    return 0;
}
Добавлено через 42 секунды
Та часть объявления функции, которая находится позади имени функции, является возвращаемым типом функции.

Добавлено через 5 минут
Что касается вашего первого вопроса, рассмотрим тогда Ваш код:

C++
1
2
3
4
5
6
7
8
void main(){
    Time t;
    int &hourRef = t.badSetHour(20);
    hourRef = 30;
    t.badSetHour(12) = 74;
        system("pause");
 
}
Создается объект типа Time, затем создается ссылка на тип int, которая инициализируется возвращенным значением метода badSetHour.

Поскольку сейчас нас не интересует внутренняя реализация ссылок, проще всего думать(как во многих книгах написано), что ссылка, это всего лишь псевдоним объекта, которым она инициализируется.

Так вот, поскольку у нас есть такой псевдоним(напомню его идентификатор hourRef), то когда мы пытаемся присвоить значение для hourRef, оно на самом деле присваивается объекту, на который указывает эта ссылка, то есть на закрытый член данных класса Time.

Отсюда вывод и одновременно ответ на Ваш вопрос:

hourRef = 30;

После этой строки hour будет принимать новое значение.
1
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
21.08.2015, 03:10  [ТС] #8
с этим разобрался.
Если я правильно понял то я создал ссылку на то, что должна вернуть функция, в данном случае переменная hours?
0
ASCII
93 / 66 / 12
Регистрация: 15.12.2013
Сообщений: 415
Завершенные тесты: 2
21.08.2015, 03:11 #9
В следующей строке у Вас также идет изменение этого члена данных, т.к. как я уже сказал, метод возвращает ссылку(псевдоним объекта), а значит есть смысл применить оператор = к вызову такого метода, после чего изменится значение ссылки.

Добавлено через 33 секунды
Цитата Сообщение от vasea_morozov Посмотреть сообщение
с этим разобрался.
Если я правильно понял то я создал ссылку на то, что должна вернуть функция, в данном случае переменная hours?
Да.
1
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
21.08.2015, 03:19  [ТС] #10
Ну что бы закрепить материал, это return возвращает ссылку на hour или этому способствовал &перед именем функции. И вообще на что он( & перед именем функции) повлиял?
0
ASCII
93 / 66 / 12
Регистрация: 15.12.2013
Сообщений: 415
Завершенные тесты: 2
21.08.2015, 03:45 #11
Лучший ответ Сообщение было отмечено vasea_morozov как решение

Решение

Цитата Сообщение от vasea_morozov Посмотреть сообщение
Ну что бы закрепить материал, это return возвращает ссылку на hour или этому способствовал &перед именем функции. И вообще на что он( & перед именем функции) повлиял?
return и прочее, это все лишь текст, который транслирует компилятор.
Когда Вы определяете функцию, то попросту говоря, Вы даете инструкции компилятору, каким образом
он должен генерировать объектный код.

Так вот. Когда вы определяете функцию, предположим таким образом:

C++
1
2
3
4
5
int &getNumber()
{
    // ... Какой-то код
    return var;
}
Мы тем самым говорим, что функция getNumber возвращает ссылку на тип int и тут уже компилятор
берет это в учет и когда дело в процессе компиляции дойдет до команды return, он уже не просто
создает ячейку памяти, в которую кладет переменную указанную в команде return, с последующей копией в переменную, которой присваивается(или инициализируется), а он в Вашем случае, где переменная является ссылкой, заставляет ссылаться эту ссылку, на возвращенное значение. Таким образом работа уже происходит не с копией, а с самим элементом.

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

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

Добавлено через 4 минуты
Ну вообще функции могут возвращать ссылки, указатели, и просто значение.
Последние два случая идентичны.
Если уж Вам так интересно, то представьте себе в самом упрощенном виде оперативную память, выделенную для работы программы как непрерывный блок данных. Представьте ячейки размером в 1 байт, много ячеек...
Не вдаваясь в подробности работы стека:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int var; // глобальная переменная, равна 0
 
// возвращает ссылку на var
int &foo()
{
    return var;
}
 
// возвращает указатель на var
int *foo()
{
    return &var;
}
 
// возвращает значение var
int foo()
{
    return var;
}
Добавлено через 2 минуты
в первом случае, если, при таком коде

C++
1
2
3
// подразумевается, что две другие функции не определены и не объявлены, чтобы
// не было неоднозначного выбора
int &lnk = foo();
Думайте так: lnk станет псевдонимом значения возвращенным функцией foo

Добавлено через 1 минуту
Во втором случае:

C++
1
2
3
// подразумевается, что две другие функции не определены и не объявлены, чтобы
// не было неоднозначного выбора
int *ptr = foo();
Произойдет следующее:
возвращаемое значение foo(), то есть адрес, будет скопирован во временную ячейку в стеке, откуда будет скопирован в ячейку памяти, выделенную под хранение адреса типа int, то есть в нашу переменную ptr.
После чего имеем возможно разыменовать этот указатель и изменить значение.

Добавлено через 3 минуты
в третьем случае:

C++
1
2
3
// подразумевается, что две другие функции не определены и не объявлены, чтобы
// не было неоднозначного выбора
int var = foo();
произойдет тоже самое, что и с указателем, данные таким же образом скопируются, но отличие в том, что возвращаемые данные функции, это значение переменной, а не ее адрес. То есть переменная var получит копию ее значения.

В то время как при вызове версии для ссылки, мы можем изменить значение на которое она ссылается.
В случае же с возвращаем по значению(последний вариант), если мы попытаемся изменить значение переменной var, будет изменено ее значение, которое всего лишь копия объекта.

Добавлено через 3 минуты
Конечно, ссылка скорей всего в компиляторе реализована как указатель, но это нас не касается.
Главное думать о ссылках, что это не объекты, а псевдонимы объектов.
Так как любое выражение с участием ссылки, будет на самом деле выражением с участием реального объекта, на который она ссылается. Именно по этой причине нет возможности изменить объект на который ссылается ссылка. Поэтому ссылки всегда надо инициализировать.

Добавлено через 33 секунды
Вообще мне кажется, о таком сейчас Вам не стоит задумываться. Просто изучите поведение ссылок и пишите код, практикуйтесь, потом само придет.
1
vasea_morozov
0 / 0 / 0
Регистрация: 18.06.2014
Сообщений: 16
21.08.2015, 14:09  [ТС] #12
Большое спасибо! теперь я понял всё,о чём спрашивал!)
0
Avazart
Эксперт С++
7717 / 5626 / 549
Регистрация: 10.12.2010
Сообщений: 25,322
Записей в блоге: 17
21.08.2015, 18:32 #13
C++
1
2
3
4
int &badSetHour(int hh){
        hour = (hh >= 0 && hh < 24) ? hh : 0;
        return hour;
    };
Стоило вероято начать с того что эта функция делает не понятно что, т.е намерения программиста не очевидны.
Зная что хотел сделать программист можно было бы написать более корректный и очевидный пример.
0
Tulosba
:)
Эксперт С++
4747 / 3241 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
22.08.2015, 14:34 #14
Цитата Сообщение от ASCII Посмотреть сообщение
возвращаемый тип данных в некоторых ситуациях влияет на то, что вернет функция
В некоторых? Я бы сказал, что во всех!
Цитата Сообщение от ASCII Посмотреть сообщение
нет возможности изменить объект на который ссылается ссылка
Неудачная формулировка. Изменить объект можно, но нельзя изменить связь м/у ссылочной переменной и объектом, на который ссылка указывает.

Проводя аналогию с указателями, можно было бы сказать, что ссылка (T&) работает как константный указатель на объект:
C++
1
T* const x = &t; // можно менять данные через 'x', но нельзя сделать чтобы 'x' указывал на объект, отличный от 't'
а ссылка на константу (const T&) - как константный указатель на константный объект:
C++
1
const T* const x = &t; // нельзя менять данные через 'x', и нельзя сделать чтобы 'x' указывал на объект, отличный от 't'
Цитата Сообщение от Avazart Посмотреть сообщение
Стоило вероято начать с того что эта функция делает не понятно что
Это да, но ТС пока ещё учится и лепит всё в кучу, так что простительно.
Обычно сеттеры либо возвращают void (в большинстве случаев), либо предыдущее установленное значение.
0
Avazart
Эксперт С++
7717 / 5626 / 549
Регистрация: 10.12.2010
Сообщений: 25,322
Записей в блоге: 17
22.08.2015, 14:37 #15
Цитата Сообщение от Tulosba Посмотреть сообщение
Это да, но ТС пока ещё учится и лепит всё в кучу, так что простительно.
Спорный вопрос, возможно стоит стремиться сразу же учиться правильно выражать свои мысли в коде.
0
Radugaga
6 / 6 / 0
Регистрация: 03.08.2015
Сообщений: 25
22.08.2015, 14:57 #16
Цитата Сообщение от Avazart Посмотреть сообщение
Стоило вероято начать с того что эта функция делает не понятно что
Цитата Сообщение от Tulosba Посмотреть сообщение
Это да, но ТС пока ещё учится и лепит всё в кучу, так что простительно.
TC не лепит. Программа взята у Дейтелов "Как программировать на C++"
0
Миниатюры
Возврат ссылки на закрытый элемент данных с++  
Avazart
Эксперт С++
7717 / 5626 / 549
Регистрация: 10.12.2010
Сообщений: 25,322
Записей в блоге: 17
22.08.2015, 15:15 #17
А тогда понятен контекст...
Только пример не очень.
Думаю понятно тут акцент на том что возвращая ссылку мы даем возможность задать значения в обход валидации -это плохо.
А по сути там не должно быть ссылки потому что недолжно... т.е она там не нужна, у нас возвращается простой тип int так что ссылка не нужна.
0
Radugaga
6 / 6 / 0
Регистрация: 03.08.2015
Сообщений: 25
22.08.2015, 15:26 #18
Цитата Сообщение от Avazart Посмотреть сообщение
А по сути там не должно быть ссылки потому что недолжно... т.е она там не нужна, у нас возвращается простой тип int так что ссылка не нужна.
так это только обучающая программа

Цитата Сообщение от vasea_morozov Посмотреть сообщение
Как устроена проблема с возвратом ссылки на закрытый элемент данных.
Цитата Сообщение от vasea_morozov Посмотреть сообщение
int &hourRef = t.badSetHour(20);
представьте это в таком виде
C++
1
2
Time t;
int &hourRef = t.hour;
и все станет ясно
1
ASCII
93 / 66 / 12
Регистрация: 15.12.2013
Сообщений: 415
Завершенные тесты: 2
23.08.2015, 18:14 #19
Цитата Сообщение от Tulosba Посмотреть сообщение
Неудачная формулировка. Изменить объект можно, но нельзя изменить связь м/у ссылочной переменной и объектом, на который ссылка указывает.
Проводя аналогию с указателями, можно было бы сказать, что ссылка (T&) работает как константный указатель на объект:
Ну можно было, да, но это бы еще больше его запутало. Т.к. пришлось бы объяснять верхний и нижний уровень модификатора типа const. К тому же большинство новичков юзают VS, где разрешена такая запись:

C++
1
const int & const lnk = objI;
В то время как например GCC выдаст ошибку: const qualifiers cannot be applied to const int&.
На счет неудачной формулировки связи ссылки с объектом, согласен, запутанно выразился.
1
Tulosba
:)
Эксперт С++
4747 / 3241 / 497
Регистрация: 19.02.2013
Сообщений: 9,046
23.08.2015, 22:27 #20
Цитата Сообщение от ASCII Посмотреть сообщение
VS, где разрешена такая запись:
VS давно известна своим отступлением от Стандарта. Хотя в данном случае и выводит предупреждение:
warning C4227: anachronism used : qualifiers on reference are ignored
Я же предпочитаю в первую очередь полагаться на Стандарт, и только потом на особенности в реализации того или иного компилятора.
В Стандарте на тему квалификаторов у ссылок сказано довольно четко (8.3.2/1):
Cv-qualified references are ill-formed except when the cv-qualifiers are introduced through the use of a typedef-name (7.1.3, 14.1) or decltype-specifier (7.1.6.2), in which case the cv-qualifiers are ignored.
1
23.08.2015, 22:27
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.08.2015, 22:27

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

Возврат ссылки на локальную переменную
Привет, есть такой код: int*&amp; change(void) { int* x(new int(50));...

Возврат ссылки на указатель из функции
#include &lt;iostream&gt; int*&amp; getPtrRef(int*&amp; ref) { int*&amp; cpy = ref; ...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

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