Позволил себе вынести
эту веткуАвтор: Павел Кузнецов
Дата: 07.11.04
сюда т.к. не могу писать в том форуме но хотелось бы поддержать этих товарищей. Заранее приношу извинения если что не так.
ПК>Средства для обеспечения инкапсуляции есть и в C. При этом получающаяся инкапсуляция ничуть не "меньше", чем в C++.
Средства для обеспечения инкапсуляции есть и в Си, но они намного примитивнее чем в С++, о чем и говорил VladD2. См. выделенный вопрос ниже чтобы понять почему "меньше."
ПК>Ты привел неэквивалентный с точки зрения инкапсуляции пример на C. Но это не означает, что нельзя написать эквивалентный в этом отношении пример на C. Вот он:
Влад, как раз-таки, привел правильный пример, корректно демонстрирующий почему инкапсуляция в Си примитивнее, а вот Вы нет. Опять-таки, смотрите выделенный вопрос ниже.
И думаете такое (ваш пример) нельзя сделать на С++?
ПК>Заголовочный файл:
ПК>ПК>typedef int ErrorCode;
ПК>#define A_OK ((ErrorCode)0)
ПК>// Требования инкапсуляции не допускают установку
ПК>// отрицальтного значения свойству Val.
ПК>//
ПК>#define A_ERROR_INVALID_VAL ((ErrorCode)-1)
ПК>typedef struct Atag A;
ПК>A* create_A(void);
ПК>void delete_A(A*);
ПК>int A_getVal(A*);
ПК>ErrorCode A_setVal(A*, int);
ПК>
У Вас тут Atag не объявлен, и я не совсем уверен, что в Си можно писать struct Atag; чтобы объявить имя, но это неважно.
ПК>Файл с реализацией:
ПК>ПК>. . .
ПК>struct Atag
ПК>{
ПК> int _val;
ПК>};
ПК>A* create_A(void)
ПК>{
ПК> A* a = (A*)malloc(sizeof(A));
ПК> return a;
ПК>}
ПК>void delete_A(A* a)
ПК>{
ПК> free(a);
ПК>}
ПК>int A_getVal(A* a)
ПК>{
ПК> return a->_val;
ПК>}
ПК>ErrorCode setVal(A* a, int val)
ПК>{
ПК> if (val < 0)
ПК> return A_ERROR_INVALID_VAL;
a->>_val = val;
ПК> return A_OK;
ПК>}
ПК>
ПК>Использование:
ПК>ПК>int main()
ПК>{
ПК> A* a;
ПК> ErrorCode err_code;
ПК> a = create_A();
ПК> if (!a)
ПК> return -1;
ПК> err_code = 0;
ПК> . . .
ПК> if (err_code != A_OK)
ПК> err_code = A_setVal(a, 123); // OK
ПК> if (err_code != A_OK)
ПК> err_code = A_setVal(a, -123); // Облом в рантайме.
ПК> if (err_code != A_OK)
a->>_val = -123; // Облом во время компиляции.
ПК> delete_A(a);
ПК> return err_code == A_OK ? 0 : -1;
ПК>}
ПК>
Ну а теперь сам вопрос:
А слабо Вам с Вашей инкапсуляцией создать genuine local object? Без всяких там хэндлов или указателей...
Создавать объект на хипе только для того, чтобы скрыть его детали — изврат.
>> Не думаю, что этот пример был действительно нужен.
Оказалось, что нужен т.к. позволил понять в чем заблуждается Павел,
.
ПК>Отчего же, он вполне хорошо проиллюстрировал твою позицию, здорово сэкономив нам время на ненужной риторике.
Которая (позиция) тем не менее оказалась правильной (в отличии от Вашей).
ПК>Как видишь, C вполне позволяет писать код, эквивалентный в отношении инкапсуляции коду на C++.
Как видите, Павел, Си вполне
не позволяет создать локальный объект, который бы делал "то, что нужно" в ответ на посылку какого-нибудь сообщения, выражаясь ООП терминологией.
ПК>Скажем, та же Win API в этом отношении вполне в порядке.
Win API Вы привели совершенно не к месту. Там структуры данных ядра находятся в виртуальном адресном пространстве самого ядра, и даже зная их описание, Вы все равно бы ничего не смогли сделать с ними. Использование хэндлов или дескрипторов является, имхо, единственным
естественным решением для доступа к этим структурам данных, а не по-тому что "так инкапсуляция происходит лучше." Попробуйте использовать наследие, инкапсуляцию и полиморфизм в С++, чтобы добиться такого же эффекта, что и Win API со своими хэндлами, и увидите, что не так-то это и легко. Поэтому я и использую слово "естественный."
ПК>Это в теории. На практике можно наблюдать, что многие библиотеки и API, написанные на C, лучше скрывают детали своей реализации, чем аналогичные библиотеки и API на C++.
Это чем же? Забудьте о Win API т.к. говоря о них, мы говорим о структурах данных ядра и другом адресном пространстве...
Есть библиотеки на Си которые извращаются точно так же как и извратились Вы и возвращают либо какой-нибудь хэндл или указатель на объект
в адресном пространстве процесса, но делается это не потому, что "инкапсуляция в Си лучше,"
а за неимением в Си того, что предоставляет нам С++ со своими public, protected и private. С++ в этом плане идет на шаг дальше, и поэтому Влад и говорит, что в Си инкапсуляция примитивнее чем в С++.
ПК>Попробуй, например, доступиться к внутренним структурам Windows — вряд ли это получится сделать легко: Win API достаточно хорошо изолирует тебя от внутренних деталей.
Еще бы! Структуры данных-то находятся в адресном пространстве ядра,
. См. мое объяснение выше.
ПК>А теперь давай посмотрим, скажем, на MFC... Много переменных-членов public, protected, не говоря уже о различных "внутренних" функциях с доступом public, включенных в интерфейс класса просто потому что они нужны самой MFC.
MFC не является примером для подражания, и то, о чем Вы говорите сейчас, говорит о плохом дизайне а не о поддержке инкапсуляции в языках Си и С++.
ПК>На C++ легче организовать сокрытие данных (вообще-то это вовсе не эквивалентно инкапсуляции, но на этом можно сейчас не останавливаться). Но это вовсе не означает, что сокрытие данных будет практически более эффективно, чем в C.
Не совсем понимаю, что Вы имеете здесь в виду под эффективностью, но, как я уже заметил, с Вашей инкапсуляцией на Си вы не можете создать локальный объект, который бы просто "делал свою работу." А создовать объект на хипе, чтобы скрыть его данные — это просто изврат.
> Сравнение не корректно. Команда, которая делала API Windows — была на несколько порядков опытнее <...>
ПК>Я с этим не спорю. Я только привел пример того, что на C вполне возможно писать, не выпячивая детали реализации наружу; плюс пример того, что на C++ инкапсуляция автоматически "сама собой" тоже не возникает. Именно квалификация разработчиков, с моей точки зрения, и определяет "степень инкапсулированности" того, что получится в результате. И именно поэтому я скептически отношусь к заявлениям, скажем, о "большем совершенстве С+ с точки зрения инкапсуляции".
Так-то оно так, но вот С++ больше помогает программисту избежать ошибок (своими private и public) а вот Си — нет.
09.11.04 15:58: Перенесено из 'C/C++'
некто wrote:
[]
> Ну а теперь сам вопрос: А слабо Вам с Вашей инкапсуляцией создать genuine local object? Без всяких там хэндлов или указателей... Создавать объект на хипе только для того, чтобы скрыть его детали — изврат.
А как эту проблему решает C++? Там то же самое.
[]
> Есть библиотеки на Си которые извращаются точно так же как и извратились Вы и возвращают либо какой-нибудь хэндл или указатель на объект в адресном пространстве процесса, но делается это не потому, что "инкапсуляция в Си лучше," а за неимением в Си того, что предоставляет нам С++ со своими public, protected и private. С++ в этом плане идет на шаг дальше, и поэтому Влад и говорит, что в Си инкапсуляция примитивнее чем в С++.
Вы что-то путаете: public, protected и private — это не более чем спецификаторы доступа, которые ограничивают доступ, но реализацию не скрывают; к инкапсуляции они имеют малое отношение. Инкапсуляция — это когда состояние объекта можно наблюдать и изменять вызывая соответствующии функции объекта, а не доступаясь к состоянию на прямую. Можно создать структуру без спецификаторов доступа, но с состоянием и ф-циями членами, и наслаждаться инкапсуляцией.
[]
> Так-то оно так, но вот С++ больше помогает программисту избежать ошибок (своими private и public) а вот Си — нет.
В Python нет спецификаторов доступа (private, public...) — никто не хнычит, инкапсуляция не страдает, все счастливы. Мораль: какими бы языками не пользоваться, программирование — это дисциплина во всех значениях этого слова. Программисты на "продвинутых" C# с Java'ой могут такой чепухи понаписать...
--
Maxim YegorushkinPosted via RSDN NNTP Server 1.9 gamma
Здравствуйте, Аноним, Вы писали:
А>Ну а теперь сам вопрос: А слабо Вам с Вашей инкапсуляцией создать genuine local object? Без всяких там хэндлов или указателей... Создавать объект на хипе только для того, чтобы скрыть его детали — изврат.
Чтобы сделать genuine local object, нужно знать, как минимум, его размер (и выравнивание). Ну, в общем-то, запросто...
#define A__SIZE 123
void A__ctor(void* buf, ctor-args);
void A__dtor(void* buf);
void* A__new(ctor-args) { void* p = malloc(A__SIZE); A__ctor(p, ctor-args); return p; }
void A__delete(void* p) { A__dtor(p); free(p); }
int A__foo(void* p);
void A__bar(void* p, int);
int main()
{
char a[A__SIZE];
A__ctor(a);
A__bar(a,123);
printf("%d", A__foo(a));
A__dtor(a);
}
Однако делать так — гораздо больший изврат, чем размещать объекты на куче.
И вообще, размещение объектов в статическом и автоматическом хранилище — это фича языка С++. Ну ещё TurboPascal 5.5-7.0. Больше никто так не делает — все в сад, то есть в кучу.
MaximE:
> Вы что-то путаете: public, protected и private — это не более чем спецификаторы доступа, которые ограничивают доступ, но реализацию не скрывают; к инкапсуляции они имеют малое отношение. Инкапсуляция — это когда состояние объекта можно наблюдать и изменять вызывая соответствующии функции объекта, а не доступаясь к состоянию на прямую. Можно создать структуру без спецификаторов доступа, но с состоянием и ф-циями членами, и наслаждаться инкапсуляцией.
Что-то здесь не так
Какие задачи решает такая инкапсуляция?
Как называется концепция, для поддержки которой были введены спецификаторы доступа public, protected и private?
[]
Posted via RSDN NNTP Server 1.9 gamma
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Здравствуйте, folk, Вы писали:
F>MaximE:
>> Вы что-то путаете: public, protected и private — это не более чем спецификаторы доступа, которые ограничивают доступ, но реализацию не скрывают; к инкапсуляции они имеют малое отношение. Инкапсуляция — это когда состояние объекта можно наблюдать и изменять вызывая соответствующии функции объекта, а не доступаясь к состоянию на прямую. Можно создать структуру без спецификаторов доступа, но с состоянием и ф-циями членами, и наслаждаться инкапсуляцией.
F>Что-то здесь не так
F>Какие задачи решает такая инкапсуляция?
Решает пару задач — запрещает оперирование состоянием объекта напрямую — это то что делают private-public и интерфейсы; скрывает реализацию объекта — это то, что делают только интерфейсы (+pimpl) .
F>Как называется концепция, для поддержки которой были введены спецификаторы доступа public, protected и private?
См. выще. Не уверен, что была какая-то фундаментальная концепция.
MaximE:
> >> Вы что-то путаете: public, protected и private — это не более чем спецификаторы доступа, которые ограничивают доступ, но реализацию не скрывают; к инкапсуляции они имеют малое отношение. Инкапсуляция — это когда состояние объекта можно наблюдать и изменять вызывая соответствующии функции объекта, а не доступаясь к состоянию на прямую. Можно создать структуру без спецификаторов доступа, но с состоянием и ф-циями членами, и наслаждаться инкапсуляцией.
>
> F>Что-то здесь не так
> F>Какие задачи решает такая инкапсуляция?
>
> Решает пару задач — запрещает оперирование состоянием объекта напрямую — это то что делают private-public и интерфейсы; скрывает реализацию объекта — это то, что делают только интерфейсы (+pimpl) .
Не понял, как "структура без спецификаторов доступа, но с состоянием и ф-циями членами" запрещает оперирование состоянием объекта напрямую? Все же открыто для публики.
> F>Как называется концепция, для поддержки которой были введены спецификаторы доступа public, protected и private?
>
> См. выще. Не уверен, что была какая-то фундаментальная концепция.
Абзацем выше ты вроде согласился что public-private имеют отношение к инкапсуляции
Если хочешь поговорить об этом, то лучше это делать в топике "Суть понятия инкапсуляции" по соседству.
Вижу у меня серьезные проблемы с пониманием собеседников
Posted via RSDN NNTP Server 1.9 gamma
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн