Как можно написать объектно-ориентированный код на C? Особенно в отношении полиморфизма.
См. Также этот вопрос переполнения стека Объект-ориентация в Си .
Как можно написать объектно-ориентированный код на C? Особенно в отношении полиморфизма.
См. Также этот вопрос переполнения стека Объект-ориентация в Си .
Ответы:
Да. На самом деле Аксель Шрайнер бесплатно предоставляет свою книгу «Объектно-ориентированное программирование в ANSI-C», которая довольно подробно освещает эту тему.
источник
Поскольку вы говорите о полиморфизме, то да, вы можете, мы занимались такими вещами за годы до появления C ++.
В основном вы используете a
struct
для хранения данных и списка указателей функций для указания на соответствующие функции для этих данных.Итак, в классе связи у вас будет вызов open, read, write и close, который будет поддерживаться в виде четырех указателей на функции в структуре наряду с данными для объекта, что-то вроде:
Конечно, те сегменты кода, приведенные выше, на самом деле будут в «конструкторе», таком как
rs232Init()
.Когда вы «наследуете» от этого класса, вы просто меняете указатели, чтобы они указывали на ваши собственные функции. Каждый, кто вызывал эти функции, делал бы это с помощью указателей на функции, давая вам ваш полиморфизм:
Вроде как ручной vtable.
Вы могли бы даже иметь виртуальные классы, установив указатели на NULL - поведение будет немного отличаться от C ++ (дамп ядра во время выполнения, а не ошибка во время компиляции).
Вот пример кода, который демонстрирует это. Сначала структура класса верхнего уровня:
Тогда у нас есть функции для подкласса TCP:
И HTTP один, а также:
И, наконец, тестовая программа, чтобы показать это в действии:
Это производит вывод:
так что вы можете видеть, что различные функции вызываются в зависимости от подкласса.
источник
tCommClass
будет переименованtCommVT
, аtCommClass
структура будет иметь только поля данных и одноtCommVT vt
поле, указывающее на «одну-единственную» виртуальную таблицу. Перенос всех указателей с каждым экземпляром добавляет ненужные накладные расходы и напоминает больше о том, как вы будете делать вещи в JavaScript, чем в C ++, ИМХО.Пространства имен часто создаются следующим образом:
вместо
Чтобы превратить структуру C в нечто вроде класса C ++, вы можете превратить:
В
И делать:
Я не делал деструктор и не удалял, но он следует той же схеме.
this_is_here_as_an_example_only похож на статическую переменную класса, которая используется всеми экземплярами типа. Все методы действительно статичны, за исключением того, что некоторые принимают this *
источник
st->my_type->push(st, thing2);
вместоst->my_type.push(st, thing2);
struct stack_type my_type;
вместоstruct stack_type * my_type;
Class
структуры? Это сделало бы OO C более динамичным, чем C ++. Как насчет этого? Кстати, +1.Я считаю, что помимо того, что ООП в Си полезен сам по себе, он является отличным способом изучения ООП и понимания его внутренней работы. Опыт многих программистов показал, что для эффективного и уверенного использования техники программист должен понимать, как в конечном итоге реализуются базовые концепции. Эмуляция классов, наследования и полиморфизма в C учит именно этому.
Чтобы ответить на оригинальный вопрос, вот пара ресурсов, которые учат, как сделать ООП в C:
В блоге EmbeddedGurus.com «Объектно-ориентированное программирование на C» показано, как реализовать классы и единичное наследование в переносимом C: http://embeddedgurus.com/state-space/2008/01/object-based-programming-in-c /
Замечание по применению "" C + "- объектно-ориентированное программирование на C" показывает, как реализовать классы, одиночное наследование и позднее связывание (полиморфизм) в C с использованием макросов препроцессора: http://www.state-machine.com/resources/cplus_3. 0_manual.pdf , пример кода доступен по адресу http://www.state-machine.com/resources/cplus_3.0.zip
источник
Я видел это сделано. Я бы не рекомендовал это. C ++ изначально начинал этот путь как препроцессор, который создавал код на C как промежуточный этап.
По сути, в конечном итоге вы создаете таблицу диспетчеризации для всех ваших методов, где храните ссылки на функции. Извлечение класса повлечет за собой копирование этой таблицы диспетчеризации и замену записей, которые вы хотите переопределить, с вашими новыми «методами», вызывающими исходный метод, если он хочет вызвать базовый метод. В конечном итоге вы переписываете C ++.
источник
glib
написано в C в объективном смысле?Конечно, это возможно. Это то , что делает GObject , фреймворк, на котором основаны все GTK + и GNOME .
источник
Подбиблиотека FILE C stdio - отличный пример того, как создать абстракцию, инкапсуляцию и модульность в чистом C.
Наследование и полиморфизм - другие аспекты, которые часто считаются важными для ООП, - не обязательно обеспечивают повышение производительности, которое они обещают, и были выдвинуты разумные аргументы , что они могут фактически препятствовать развитию и размышлениям о проблемной области.
источник
Тривиальный пример с животными и собаками: вы отражаете механизм vtable C ++ (во всяком случае, в любом случае). Вы также разделяете распределение и создание экземпляров (Animal_Alloc, Animal_New), чтобы мы не вызывали malloc () несколько раз. Мы также должны явно передать
this
указатель.Если бы вы делали не виртуальные функции, это тривиально. Вы просто не добавляете их в vtable, а статические функции не требуют
this
указателя. Множественное наследование обычно требует нескольких таблиц для устранения неоднозначностей.Кроме того, вы должны иметь возможность использовать setjmp / longjmp для обработки исключений.
PS. Это проверено на компиляторе C ++, но должно быть легко заставить его работать на компиляторе C.
источник
typedef
Внутри этоstruct
невозможно в C.Проверьте GObject . Это должно быть ОО в С и одна реализация того, что вы ищете. Если вы действительно хотите использовать OO, используйте C ++ или другой язык OOP. Иногда с GObject может быть очень сложно работать, если вы привыкли иметь дело с ОО-языками, но, как и все остальное, вы привыкнете к соглашениям и потоку.
источник
Это было интересно читать. Я сам размышлял над тем же вопросом, и польза от размышлений заключается в следующем:
Попытка представить, как реализовать концепции ООП на языке, отличном от ООП, помогает мне понять сильные стороны языка ООП (в моем случае, C ++). Это помогает мне лучше понять, использовать ли C или C ++ для приложения определенного типа - где преимущества одного перевешивают другое.
Просматривая в Интернете информацию и мнения по этому вопросу, я обнаружил автора, который писал код для встроенного процессора и имел только доступный компилятор C: http://www.eetimes.com/discussion/other/4024626/Object-Oriented -С-Создание-Foundation-классы-Part-1
В его случае анализ и адаптация ООП-концепций в простом С были вполне обоснованными. Похоже, он был готов пожертвовать некоторыми концепциями ООП из-за снижения производительности, вызванного попыткой реализовать их в C.
Урок, который я извлек, заключается в том, что да, это можно сделать в определенной степени, и да, есть несколько веских причин, чтобы попробовать это.
В конце концов, машина перебирает биты указателя стека, заставляя счетчик программ перемещаться и вычисляя операции доступа к памяти. С точки зрения эффективности, чем меньше таких вычислений выполняется вашей программой, тем лучше ... но иногда нам приходится платить этот налог просто, чтобы мы могли организовать нашу программу таким образом, чтобы она была менее подвержена человеческим ошибкам. Компилятор языка ООП стремится оптимизировать оба аспекта. Программист должен быть намного осторожнее при реализации этих концепций на языке, подобном C.
источник
Возможно, вам будет полезно взглянуть на документацию Apple, касающуюся набора API Core Foundation. Это чистый API C, но многие типы связаны с объектными эквивалентами Objective C.
Вам также может быть полезно взглянуть на дизайн самой Objective-C. Он немного отличается от C ++ в том, что объектная система определяется в терминах функций C, например,
objc_msg_send
для вызова метода объекта. Компилятор переводит синтаксис в квадратные скобки в эти вызовы функций, так что вам не нужно это знать, но, учитывая ваш вопрос, вам может быть полезно узнать, как он работает под капотом.источник
Есть несколько методов, которые можно использовать. Самый важный из них - как разделить проект. В нашем проекте мы используем интерфейс, который объявлен в файле .h, а реализацию объекта - в файле .c. Важной частью является то, что все модули, которые включают в себя файл .h, видят только объект как a
void *
, и файл .c является единственным модулем, который знает внутреннюю часть структуры.Примерно так для класса мы называем FOO в качестве примера:
В .h файле
Файл реализации C будет примерно таким.
Поэтому я даю указатель явно на объект для каждой функции этого модуля. Компилятор C ++ делает это неявно, а в C мы записываем это явно.
Я действительно использую
this
в своих программах, чтобы убедиться, что моя программа не компилируется в C ++, и у меня есть прекрасное свойство быть в другом цвете в моем редакторе подсветки синтаксиса.Поля FOO_struct могут быть изменены в одном модуле, и другой модуль даже не нужно перекомпилировать, чтобы все еще использовать.
С этим стилем я уже рассмотрел большую часть преимуществ ООП (инкапсуляция данных). Используя указатели функций, даже легко реализовать что-то вроде наследования, но, честно говоря, это действительно редко используется.
источник
typedef struct FOO_type FOO_type
вместо typedef значение void в заголовке, вы получите дополнительное преимущество проверки типов, но при этом не будете подвергать свою структуру.Вы можете подделать его, используя указатели функций, и фактически, я думаю, теоретически возможно скомпилировать программы на C ++ в C.
Однако редко имеет смысл навязывать парадигму языку, а не выбирать язык, использующий эту парадигму.
источник
Можно сделать объектно-ориентированный C, я видел такой код в производстве в Корее, и это был самый ужасный монстр, которого я видел за последние годы (это было как в прошлом году (2007), когда я видел код). Так что да, это может быть сделано, и да, люди делали это раньше, и до сих пор делают это даже в наши дни. Но я бы порекомендовал C ++ или Objective-C, оба языка родились из C, с целью обеспечения объектной ориентации с различными парадигмами.
источник
Если вы убеждены в том, что подход ООП лучше, чем проблема, которую вы пытаетесь решить, почему вы пытаетесь решить ее с помощью языка не-ООП? Кажется, вы используете не тот инструмент для работы. Используйте C ++ или другой объектно-ориентированный вариант языка C.
Если вы спрашиваете, потому что вы начинаете кодировать уже существующий большой проект, написанный на C, то вам не следует пытаться навязывать свои собственные (или чьи-либо) парадигмы ООП в инфраструктуре проекта. Следуйте инструкциям, которые уже присутствуют в проекте. В целом, чистые интерфейсы и изолированные библиотеки и модули будут идти длинный путь к имея чистую OOP- иш дизайн.
Если после всего этого вы действительно настроены на выполнение ООП C, прочитайте это (PDF).
источник
Да, ты можешь. Люди писали объектно-ориентированный C до появления C ++ или Objective-C . И C ++, и Objective-C частично пытались взять некоторые концепции ОО, используемые в C, и формализовать их как часть языка.
Вот действительно простая программа, которая показывает, как вы можете сделать что-то похожее на / вызов метода (есть лучшие способы сделать это. Это просто доказательство того, что язык поддерживает концепции):
источник
Конечно, это будет не так красиво, как использование языка со встроенной поддержкой. Я даже написал «объектно-ориентированный ассемблер».
источник
Небольшой код OOC для добавления:
источник
Я копал это в течение одного года:
Поскольку систему GObject сложно использовать с чистым C, я попытался написать несколько хороших макросов, чтобы облегчить стиль OO с помощью C.
Вот мой сайт проекта (у меня нет достаточно времени, чтобы написать en. Doc, однако документация на китайском намного лучше).
OOC-GCC
источник
Существует пример наследования с использованием C в 1996 году разговора Джима Ларсона приведен в Разделе 312 Программирования LunchTime семинара здесь: высокий и низкий уровень C .
источник
Дейв Хэнсон C Интерфейсы и Реализация является отличными на инкапсуляцию и обозначении и очень хорошо на использовании указателей на функцию. Дейв не пытается имитировать наследование.
источник
ООП - это всего лишь парадигма, которая ставит данные как более важные, чем код в программах. ООП это не язык. Итак, как простой C является простым языком, ООП в простом C также прост.
источник
Одна вещь, которую вы, возможно, захотите сделать, это изучить реализацию инструментария Xt для X Window . Конечно, он становится длиннее в зубе, но многие из используемых структур были разработаны для работы в ОО-стиле в рамках традиционного С. Как правило, это означает добавление дополнительного слоя косвенности тут и там и конструирование структур для наложения друг на друга.
Таким образом, вы действительно можете многое сделать, если OO находится в C, хотя иногда кажется, что концепции OO не возникли полностью из разума
#include<favorite_OO_Guru.h>
. Они действительно составляли многие из признанных лучших практик того времени. ОО языки и системы только дистиллированные и усиленные части программирования времени.источник
Ответ на вопрос «Да, вы можете».
Объектно-ориентированный C (OOC) комплект предназначен для тех, кто хочет программировать объектно-ориентированным образом, но также придерживается старого доброго C. OOC реализует классы, одиночное и множественное наследование, обработку исключений.
особенности
• Использует только макросы и функции Си, языковые расширения не требуются! (ANSI-C),
• Легко читаемый исходный код для вашего приложения. Забота была сделана, чтобы сделать вещи максимально простыми.
• Одиночное наследование классов
• Множественное наследование по интерфейсам и миксинам (начиная с версии 1.3)
• Реализация исключений (в чистом C!)
• Виртуальные функции для занятий
• Внешний инструмент для легкой реализации класса
Для получения более подробной информации посетите http://ooc-coding.sourceforge.net/ .
источник
Кажется, что люди пытаются эмулировать стиль C ++, используя C. Я предполагаю, что в объектно-ориентированном программировании C действительно есть структурно-ориентированное программирование. Тем не менее, вы можете достичь таких вещей, как позднее связывание, инкапсуляция и наследование. Для наследования вы явно определяете указатель на базовые структуры в вашей подструктуре, и это, очевидно, форма множественного наследования. Вам также необходимо определить, если ваш
скомпилировать с
c_compiler main.c inherited_class_1.obj inherited_class_2.obj private_class.obj
.Поэтому совет должен придерживаться чистого стиля C, а не пытаться форсировать стиль C ++. Также этот способ предоставляет очень чистый способ создания API.
источник
См. Http://slkpg.byethost7.com/instance.html еще один поворот ООП в C. Он подчеркивает данные экземпляра для повторного входа с использованием только нативного C. Множественное наследование выполняется вручную с помощью функций-оболочек. Тип безопасности сохраняется. Вот небольшой образец:
источник
Я немного опаздываю на вечеринку, но я хочу поделиться своим опытом по этой теме: я работаю со встроенными компонентами в настоящее время, и единственный (надежный) компилятор, который у меня есть, это C, так что я хочу применить объектно-ориентированный подход во встроенных проектах, написанных на C.
Большинство решений, которые я видел до сих пор, интенсивно использует типы типов, поэтому мы теряем безопасность типов: компилятор не поможет вам, если вы допустите ошибку. Это совершенно недопустимо.
Требования, которые у меня есть:
Я подробно объяснил свой подход в этой статье: объектно-ориентированное программирование на C ; Кроме того, есть утилита для автогенерации шаблонного кода для базовых и производных классов.
источник
Я построил небольшую библиотеку, где я попробовал это, и для меня это работает очень хорошо. Вот я и поделился опытом.
https://github.com/thomasfuhringer/oxygen
Одиночное наследование может быть реализовано довольно легко, используя структуру и расширяя ее для любого другого дочернего класса. Простое приведение к родительской структуре позволяет использовать родительские методы для всех потомков. Если вы знаете, что переменная указывает на структуру, содержащую объект такого типа, вы всегда можете привести ее к корневому классу и выполнить самоанализ.
Как уже упоминалось, виртуальные методы несколько сложнее. Но они выполнимы. Для простоты я просто использую массив функций в структуре описания класса, который каждый дочерний класс копирует и, при необходимости, заполняет отдельные слоты.
Многократное наследование будет довольно сложным для реализации и приведет к значительному снижению производительности. Так что я оставляю это. Я считаю желательным и полезным во многих случаях четко моделировать реальные жизненные обстоятельства, но, вероятно, в 90% случаев единственное наследование покрывает потребности. А одиночное наследование простое и ничего не стоит.
Также меня не волнует безопасность типов. Я думаю, что вы не должны зависеть от компилятора, чтобы предотвратить ошибки программирования. И это в любом случае ограждает вас от довольно небольшой части ошибок.
Как правило, в объектно-ориентированной среде вы также хотите реализовать подсчет ссылок для максимально возможной автоматизации управления памятью. Поэтому я также поместил счетчик ссылок в корневой класс «Объект» и некоторые функции для инкапсуляции выделения и освобождения памяти кучи.
Это все очень просто и скудно и дает мне основы ОО, не заставляя меня иметь дело с монстром, который является C ++. И я сохраняю гибкость пребывания на земле C, что, среди прочего, облегчает интеграцию сторонних библиотек.
источник
Я предлагаю использовать Objective-C, который является надмножеством C.
Хотя Objective-C 30 лет, он позволяет писать элегантный код.
http://en.wikipedia.org/wiki/Objective-C
источник
Да, но я никогда не видел, чтобы кто-нибудь пытался реализовать какой-либо полиморфизм с C.
источник