Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.52/21: Рейтинг темы: голосов - 21, средняя оценка - 4.52
34 / 34 / 37
Регистрация: 21.06.2012
Сообщений: 152
1

Нарушение инкапсуляции или нет?

16.07.2017, 23:51. Показов 3941. Ответов 24
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
В общем экспериментируя с крестами сделал такую штуку и не могу понять это нарушение инкапсуляции или нет?
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
#include <iostream>
 
class Bar;
 
class Foo {
public:
    Foo() : a(100) {}
    friend std::ostream& operator<<(std::ostream& os, const Foo& foo)
    {
        os << foo.a;
        return os;
    }
private:
    int a;
    friend class Bar;
};
 
class Bar {
public:
    static int Foo::* getPrivateFieldA()
    {
        return &Foo::a;
    };
};
 
 
int main()
{
    Foo *foo = new Foo();
    std::cout << *foo << std::endl;
    foo->*(Bar::getPrivateFieldA()) /= 2;
    std::cout << *foo << std::endl;
    return 0;
}
Почему можно получить доступ к приватному полю Foo через адрес на поле класса (а не объекта) сгенерированном в дружественном Foo классе Bar? По идеи доступ к приватному полю даже через адрес на него через класс можно получать только в Bar (в дружественных классах т.е.), но почему это получается в сторонних функциях (тут main)? Это нормально или я сломал кресты? Уже несколько дней мучает этот вопрос.
1
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.07.2017, 23:51
Ответы с готовыми решениями:

Нарушение инкапсуляции или нет?
Есть такой код: class Tune { private: vector&lt;int&gt; A; public: const vector&lt;int&gt;&amp; get_A()...

Нарушение инкапсуляции метода
Уважаемые, опытные, подскажите, чем может грозить нарушение инкапсуляции метода класса, кроме того...

Нарушение авторского права или нет?
Здравствуйте, буду благодарна за подсказку от знающих людей. Если заказчик приносит вам...

Нарушение закона обавторском праве или нет?
У меня мама работает в школе, а значит можно устанавливать на её компьютер школьное п/о. Захожу я...

24
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
17.07.2017, 22:15 21
Author24 — интернет-сервис помощи студентам
h3mbr0,
Интересный пример, но минусов там много

Опишу основные;

1) Казалось бы мы хотели дать доступ только к методу установки имени, а в итоге дали доступ ко всем протектедам и прайветам. В итоге остаётся возможность изменить те поля которые не предназначены для модификации извне. Да, можно надеяться на то что все кто будут работать с этим кодом будут внимательны и сообразят не прибегать к иным ухищрениям, но с таким же успехом тот самый метод можно сделать public и так же положиться на внимательность программистов и полагать, что метод setName класса Child будет вызываться только из класса Mother.

2) Вызовы разрешённые только в определённых контекстах как в том примере, создают путаницу особенно если проект большой и таких вызовов много. Глядя на такой код нельзя сходу определить чего именно можно вызывать дружественному классу а чего нет. Без friend же достаточно взглянуть на внешний интерфейс и все, никаких заморочек.

3) Такой дизайн насколько я помню нельзя описать при помощи таких штучек UML

4) Смысл приватных и защищённых членов немного в другом. Они нужны что бы скрыть детали реализации, и иметь возможность разработчику этих деталей манипулировать ими по нужде, отражая изменения для вызывающей стороны без изменения внешнего интерфейса - это и есть основное назначение всех этих модификаторов (протектед, прайвет).

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

Умножение на два это был простой пример. На практике как правило все гораздо сложнее.

Вот почему детали не должны нас волновать. Когда человек садится за руль ему все равно чего там у него сейчас под капотом, его не интересуют эти детали, которые производитель может заменить в любое время. Все что интересно водителю это наружний интерфейс, тобишь крутить педали...
0
rikimaru2013
17.07.2017, 22:16
  #22

Не по теме:

5 часов сидел, обновлял страницу - ждал драки с hoggy - а он не пришёл(((( А с Nosey по 9 страниц холиварят ((((

0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
17.07.2017, 22:38 23
Цитата Сообщение от rikimaru2013 Посмотреть сообщение
Класс Foo доверился классу Bar полностью. А тот в свою очередь уверено, может предоставлять доступ в публичном интерфейсе всем желающим - он ведь понимает, что он делает.
что такое вообще "инкапсуляция" ?
это - языковый механизм, который позволяет
оградить и защитить данные от внешнего вмешательства.

иными словами, детали внутренней реализации не зависят от внешней стороны.
а внешняя сторона не зависит от деталей реализации.

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

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

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

например - итераторы контейнеров:

C++
1
auto it = container::const_iterator(collection);
важно понимать, что итератор здесь - часть публичного интерфейса контейнера,
вынесенная в отдельный класс


здесь нет нарушения инкапсуляции,
поскольку контейнер и его итератор - один неделимый механизм,
разнесенный по двум разным классам.

конечно они зависят друг от друга.
но это точно такая же зависимость,
как зависимость отдельных частей реализации друг от дружки.
-----------------------------------------

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

тезис не лишен логики, но слегка отдает паранойей.
действительно, заполучив снаружи указатель на данные,
мы можем например забить их по delete,
а класс потом крашнется когда нибудь потом.

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

однако, посмотрите что в данном случае сливает наружу Bar?

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

Добавлено через 15 секунд

Не по теме:

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
5 часов сидел, обновлял страницу - ждал драки с hoggy - а он не пришёл(((( А с Nosey по 9 страниц холиварят ((((
эм... какие мы нетерпеливые)
я как бе почтенный глава семейства)
мне ещё работу работать и семью кормить/одевать надобно))

5
298 / 107 / 31
Регистрация: 12.03.2012
Сообщений: 449
17.07.2017, 22:43 24
Цитата Сообщение от Undisputed Посмотреть сообщение
1) Казалось бы мы хотели дать доступ только к методу установки имени, а в итоге дали доступ ко всем протектедам и прайветам. В итоге остаётся возможность изменить те поля которые не предназначены для модификации извне. Да, можно надеяться на то что все кто будут работать с этим кодом будут внимательны и сообразят не прибегать к иным ухищрениям, но с таким же успехом тот самый метод можно сделать public и так же положиться на внимательность программистов и полагать, что метод setName класса Child будет вызываться только из класса Mother.
Поскольку чтобы добавить friend class нужно модифицировать код класса, никакие ухищрения тут не работают, а добавлять friend самому - все равно что менять доступ ко всем полям на public
Если ты вмешался в код класса, то это уже другое дело, но пока все сокрыто за private и protected, а дружественный класс реализуется тем же разработчиком, для того, кто эти классы использует нет возможности получить доступ к "лишнему", для них все по-прежнему инкапсулировано

Цитата Сообщение от Undisputed Посмотреть сообщение
2) Вызовы разрешённые только в определённых контекстах как в том примере, создают путаницу особенно если проект большой и таких вызовов много. Глядя на такой код нельзя сходу определить чего именно можно вызывать дружественному классу а чего нет. Без friend же достаточно взглянуть на внешний интерфейс и все, никаких заморочек.
Глядя на большой проект обычно ничего сходу определить нельзя

Цитата Сообщение от Undisputed Посмотреть сообщение
3) Такой дизайн насколько я помню нельзя описать при помощи таких штучек UML
Вы об этом?

4 пример я не очень понял, уж извините


Цитата Сообщение от Undisputed Посмотреть сообщение
Вот почему детали не должны нас волновать. Когда человек садится за руль ему все равно чего там у него сейчас под капотом, его не интересуют эти детали, которые производитель может заменить в любое время. Все что интересно водителю это наружний интерфейс, тобишь крутить педали...
А в том то и дело, что по задумке детали остаются под капотом. В данном случае я бы рассматривал дружественные классы как единую единицу ООП, и все бы встало на свои места

Добавлено через 3 минуты
Цитата Сообщение от hoggy Посмотреть сообщение
существуют кейсы, когда классы-друзья - естественные части общего дизайна.
Лично я всегда рассматривал только такую ситуацию, и не вполне понял как может быть иначе...
0
875 / 461 / 91
Регистрация: 10.06.2014
Сообщений: 2,669
17.07.2017, 23:36 25
h3mbr0,
Так о том и речь что все что нужно и не нужно для друга становится пабликом Данные которые не должны волновать друга и не должны быть никому видны, почему то торчат наружу(это и есть открытая возможность для ухищрений). Вот если бы была возможность конкретизировать чего именно можно видеть другу а чего нет, тогда ваш пример можно было бы вытянуть А так если рассуждать по всем канонам, лучше обойтись иным подходом...

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

Насчёт UML похоже я не зря сомневался Вроде все есть для описания друзей.

Да, можно рассматривать дружественные классы как одно целое, но до поры до времени.
Сори, нормально квотировать не удаётся, пишу с мобилы
0
17.07.2017, 23:36
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.07.2017, 23:36
Помогаю со студенческими работами здесь

Можно ли по названию платы,или по чипу,или по соккету,определить,поддерживает плата ХР или нет?
Добрый день всем.Уважаемые знатоки,я заранее прошу у Вас прощенья,если заданный мной вопрос,тупой...

Ошибка с массивами, хотя формально её нет (похожи ли массивы или нет?)
Всем доброго времени суток!) В общем имею такую великолепную чтуку, она должна говорить мне,...

Нет звука или нет звуковой карты
Всем привет! помогите кто может! У меня нет звука на компе, есть преположение что на комке нет...

Вывести на экран слова, в которых все символы повторяющиеся, или сообщение «Нет», если требуемых слов нет
Дана последовательность символов, состоящая из слов. Вывести на экран слова, в которых все символы...


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

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