Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция?
Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
Функции работы с файлом как раз являются таким примером.
// Только объявляемstruct FILE;
FILE* f = fopen(...); // Создание объекта
fprintf(f, "%s", "A"); // Работа с объектом
fclose(f); // Разрушение объекта
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
Выше привели пример FILE*, он хорош и иллюстративен (используем для инкапсуляции систему модулей, вытаскиваем в заголовочники безликие дескрипторы). Но это только начало разговора. Если вы всерьёз планируете писать в ООП-стиле на C, там внутри лежит ещё много граблей, поэтому рекомендую вначале ознакомиться со state-of-art решением: системой типов и объектов GTK+.
Здравствуйте, _NN_, Вы писали:
_NN>Функции работы с файлом как раз являются таким примером.
Мне нравится обсуждение возможных проблем концепции opaque pointer, которая лежит в основе FILE*
Автор справедливо замечает: решение с opaque data type обрекает вас на выделение объектов в куче. Но это иногда может быть не совсем эффективно. А иногда -- совсем не эффективно. Как решение автор предлагает shadow data types:
Здравствуйте, Tilir, Вы писали:
T>Здравствуйте, _NN_, Вы писали:
_NN>>Функции работы с файлом как раз являются таким примером.
T>Мне нравится обсуждение возможных проблем концепции opaque pointer, которая лежит в основе FILE*
T>Автор справедливо замечает: решение с opaque data type обрекает вас на выделение объектов в куче. Но это иногда может быть не совсем эффективно. А иногда -- совсем не эффективно. Как решение автор предлагает shadow data types:
Можно еще через alloca выкрутиться или VLA C99.
Например
size_t sizeof_FILE();
FILE* f = (FILE*)alloca(sizeof_FILE()); // Выделяем на стеке
// Или так C99char c[sizeof_FILE()];
FILE* f = (FILE*)&c[0];
fcreate(f); // Вызываем конструктор
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
0) Объект -- структура.
1) Структура объявляется в двух видах, в анонимном публичном, который содержит только один массив байт, который резервирует нужный объем
данных, и в приватном внутреннем, где расписаны все поля. Первая структура не нужна, если клиента ограничить, что он может хранить объекты в своей памяти
только по ссылке. Тогда указатель на первую структуру заменяется на указатель на void (он же HANDLE).
2) Вся реализация выполняется в отдельном модуле (исходном файле). Заголовки делятся также на публичные и приватные. Клиенту класса приватные заголовки
не даются.
3) создаётся полный набор функций, манипулирующих данными объектами, часто включая создание и удаление объектов.
Здравствуйте, MasterZiv, Вы писали:
MZ>Здравствуйте, alien3128, Вы писали:
A>>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
MZ>0) Объект -- структура. MZ>1) Структура объявляется в двух видах, в анонимном публичном, который содержит только один массив байт, который резервирует нужный объем MZ>данных, и в приватном внутреннем, где расписаны все поля. Первая структура не нужна, если клиента ограничить, что он может хранить объекты в своей памяти MZ>только по ссылке. Тогда указатель на первую структуру заменяется на указатель на void (он же HANDLE). MZ>2) Вся реализация выполняется в отдельном модуле (исходном файле). Заголовки делятся также на публичные и приватные. Клиенту класса приватные заголовки MZ>не даются. MZ>3) создаётся полный набор функций, манипулирующих данными объектами, часто включая создание и удаление объектов.
Здравствуйте, Tilir, Вы писали:
T>Выше привели пример FILE*, он хорош и иллюстративен (используем для инкапсуляции систему модулей, вытаскиваем в заголовочники безликие дескрипторы). Но это только начало разговора. Если вы всерьёз планируете писать в ООП-стиле на C, там внутри лежит ещё много граблей, поэтому рекомендую вначале ознакомиться со state-of-art решением: системой типов и объектов GTK+.
жуткое извращение, кстати. в духе "мы религиозно не будем писать на С++, поэтому возьмем и переизобретем большую часть его функционала, используя убогий синтаксис и препроцессор".
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
способов может быть много, вот только вопрос — зачем, когда C++ позволяет получить не менее эффективный код с меньшими трудозатратами?
Здравствуйте, bazis1, Вы писали:
B>жуткое извращение, кстати. в духе "мы религиозно не будем писать на С++, поэтому возьмем и переизобретем большую часть его функционала, используя убогий синтаксис и препроцессор".
Основные приемы ООП были придуманы задолго до C++ и не зависят по сути от языка программирования. Никакого переизобретения.
Для выбора языка C у авторов были причины. Например, к тому времени у C уже был стандартизованный ABI, а у C++ его нет до сих пор. Но писать на C++ там тоже можно, для этого есть языковой биндинг gtkmm. А также биндинги под другие языки в количестве.
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
Только через указатели, и только на неполный тип. Т.е. в хедере что-то типа typedef struct MyData_t* Handle; Но сама структура определена в си-файле. А функции принимают объект типа Handle.
Здравствуйте, alien3128, Вы писали:
A>Коллеги, подскажите, как на языке С можно эмулировать такое свойство ООП, как инкапсуляция? A>Т.е. нужно иметь объект, все данные которого являются приватными. И должна быть возможность создавать неограниченное количество однотипных объектов.
В этой теме многие посоветовали в публичный интерфейс выставить указатель на неполный тип, а в реализации использовать полный. Но даже при сокрытии реального типа от клиента никто не запрещает исследовать память по полученному указателю и ее каким-либо образом модифицировать. В свое время MS, защищая свои структуры WINAPI, озаботилась подобным и перешла на фиктивные HANDLE, являющиеся ничем иным как ключем некой внутренней структуры, по которому реализация получает реально скрытые от глаз клиента данные. Эскиз:
// interface.htypedef int HANDLE;
HANDLE open();
void use(HANDLE);
void close(HANDLE);
// interface.c#include"interface.h"const int N=16;
struct data {
int opened;
char filename[128];
} buffer[N] = {0};
HANDLE open()
{
int h = 0;
// find free handle
...
return h;
}
void use(HANDLE h)
{
struct data* p = &buffer[h];
...
}
void close(HANDLE h)
{
buffer[h].opened = 0;
}
Здравствуйте, bazis1, Вы писали:
B>способов может быть много, вот только вопрос — зачем, когда C++ позволяет получить не менее эффективный код с меньшими трудозатратами?
Существуют продукты, где нет C++. Вот, например, линуксовое ядро (было когда-то, давно не смотрел).
Наверно, какое-нибудь ещё ядро тоже написано целиком на C.
Или микроконтроллер без компилятора C++ я вот тоже в своей жизни встречал. Или, конечно, с C++ но памяти типа 4 кбайта — "не лезет".
Ну, в общем, есть случаи, когда C практичнее.
Здравствуйте, Dair, Вы писали:
D>Здравствуйте, bazis1, Вы писали:
B>>способов может быть много, вот только вопрос — зачем, когда C++ позволяет получить не менее эффективный код с меньшими трудозатратами?
D>Существуют продукты, где нет C++. Вот, например, линуксовое ядро (было когда-то, давно не смотрел). D>Наверно, какое-нибудь ещё ядро тоже написано целиком на C.
Я и говорю, религиозные заморочки.
D>Или микроконтроллер без компилятора C++ я вот тоже в своей жизни встречал.
Только если проект имеет корни в 70х-80х годах. Сейчас в любой нише цена/мощность есть контроллеры, поддерживаемые GCC.
D>Или, конечно, с C++ но памяти типа 4 кбайта — "не лезет".
Вы просто пользоваться им не умеете. Я в свое время писал на C++ под AVR с 512 байтами (!) памяти. Inline и шаблоны позволяли переложить вещи типа "а теперь этот протокол должен использовать SPI вместо USART" на компилятор, вместо программиста. Просто не надо STL с динамической памятью туда пихать и все будет хорошо. D>Ну, в общем, есть случаи, когда C практичнее.
При условии, что вы не умеете эффективно выбрать нужный subset С++ и пользоваться им.
D>>Существуют продукты, где нет C++. Вот, например, линуксовое ядро (было когда-то, давно не смотрел). D>>Наверно, какое-нибудь ещё ядро тоже написано целиком на C. B>Я и говорю, религиозные заморочки.
D>>Или микроконтроллер без компилятора C++ я вот тоже в своей жизни встречал. B>Только если проект имеет корни в 70х-80х годах. Сейчас в любой нише цена/мощность есть контроллеры, поддерживаемые GCC.
Штатный компилятор для zOS до сих пор С++ толком не поддерживает, даже '03. Так что приходится писать на Си времен K&R.
10 лет назад та же проблема была с HP-UX, не знаю, улучшилось ли что-нибудь сейчас.
хъ
D>>Ну, в общем, есть случаи, когда C практичнее. B>При условии, что вы не умеете эффективно выбрать нужный subset С++ и пользоваться им.
Это верно, куда уж нам...
_____________________
С уважением,
Stanislav V. Zudin
Здравствуйте, Анатолий Широков, Вы писали:
АШ>Здравствуйте, bazis1, Вы писали:
АШ>Недавно писал для pic16 (microchip), в наличии есть только XC8 для этого камня. Так что, ты уж чего-то шашкой размахался на счет вездесущности С++.
мертвая платформа с меньше 0.1% долей рынка. мимо.
Здравствуйте, Stanislav V. Zudin, Вы писали:
SVZ>Штатный компилятор для zOS до сих пор С++ толком не поддерживает, даже '03. Так что приходится писать на Си времен K&R. SVZ>10 лет назад та же проблема была с HP-UX, не знаю, улучшилось ли что-нибудь сейчас.
это обычно означает, что платформа давно умерла, под нее ничего не пишут и, соответственно, нет смысла обновлять компилятор. Я не спорю, что в любой нише можно найти древнюю платформу, последний активный разработчик которой умер от старости в 199x году и там нет C++-компилятора. Я лишь утверждаю, что ориентироваться на такие платформы в 2015 году — странное занятие.
Здравствуйте, bazis1, Вы писали:
SVZ>>Штатный компилятор для zOS до сих пор С++ толком не поддерживает, даже '03. Так что приходится писать на Си времен K&R. SVZ>>10 лет назад та же проблема была с HP-UX, не знаю, улучшилось ли что-нибудь сейчас. B>это обычно означает, что платформа давно умерла, под нее ничего не пишут и, соответственно, нет смысла обновлять компилятор. Я не спорю, что в любой нише можно найти древнюю платформу, последний активный разработчик которой умер от старости в 199x году и там нет C++-компилятора. Я лишь утверждаю, что ориентироваться на такие платформы в 2015 году — странное занятие.
Это означает, что IBM, который развивает свои мейнфреймы, клал с прибором на мнение голодранцев и продолжает успешно окучивать больших и богатых клиентов. А для этих клиентов приходится разрабатывать софт.
_____________________
С уважением,
Stanislav V. Zudin