Как вы реализуете класс в C? - PullRequest
129 голосов
/ 10 сентября 2009

Предполагая, что мне нужно использовать C (без C ++ или объектно-ориентированных компиляторов), и у меня нет динамического распределения памяти, какие методы я могу использовать для реализации класса или хорошего приближения класса? Всегда ли полезно выделить «класс» в отдельный файл? Предположим, что мы можем предварительно выделить память, предполагая фиксированное количество экземпляров или даже определяя ссылку на каждый объект как константу перед временем компиляции. Не стесняйтесь делать предположения о том, какую концепцию ООП мне нужно будет реализовать (она будет отличаться) и предлагать лучший метод для каждого из них.

Ограничения:

  • Я должен использовать C, а не ООП потому что я пишу код для встроенная система, и компилятор и существующая база кода находится в C.
  • Нет динамического выделения памяти потому что у нас недостаточно памяти разумно предположить, что мы не закончим если мы начнем динамически распределять это.
  • У компиляторов, с которыми мы работаем, нет проблем с указателями на функции

Ответы [ 18 ]

3 голосов
/ 10 сентября 2009

В вашем случае хорошим приближением класса может быть ADT . Но все равно это не будет так.

3 голосов
/ 10 сентября 2009

На эту тему есть очень обширная книга, которую стоит почитать:

Объектно-ориентированное программирование в ANSI-C

3 голосов
/ 10 сентября 2009

Моя стратегия:

  • Определить весь код для класса в отдельном файле
  • Определить все интерфейсы для класса в отдельном заголовочном файле
  • Все функции-члены принимают "ClassHandle", который заменяет имя экземпляра (вместо o.foo (), вызов foo (oHandle)
  • Конструктор заменяется функцией void ClassInit (ClassHandle h, int x, int y, ...) ИЛИ ClassHandle ClassInit (int x, int y, ...) в зависимости от стратегии выделения памяти
  • Все переменные-члены хранятся в виде элемента статической структуры в файле класса, инкапсулируя его в файл, предотвращая доступ к нему внешних файлов
  • Объекты хранятся в массиве статической структуры, приведенной выше, с предопределенными дескрипторами (видимыми в интерфейсе) или фиксированным пределом объектов, которые могут быть созданы
  • Если это полезно, класс может содержать открытые функции, которые будут проходить по циклу через массив и вызывать функции всех экземпляров объектов (RunAll () вызывает каждый Run (oHandle)
  • Функция Deinit (ClassHandle h) освобождает выделенную память (индекс массива) в стратегии динамического выделения

Кто-нибудь видит какие-либо проблемы, дыры, потенциальные подводные камни или скрытые преимущества / недостатки любого варианта этого подхода? Если я заново изобретаю метод проектирования (и я полагаю, что должен быть), можете ли вы указать мне его название?

2 голосов
/ 10 сентября 2009

Мой подход состоит в том, чтобы переместить функции struct и все , в основном связанные * , в отдельный исходный файл (-ы), чтобы его можно было использовать "переносимо".

В зависимости от вашего компилятора, вы можете иметь возможность включать функции в struct, но это очень расширение, специфичное для компилятора, и не имеет ничего общего с последним версия стандарта, которую я обычно использовал:)

2 голосов
/ 31 марта 2013

GTK полностью построен на C и использует множество концепций ООП. Я прочитал исходный код GTK, и он довольно впечатляющий и определенно легче для чтения. Основная концепция заключается в том, что каждый «класс» представляет собой просто структуру и связанные статические функции. Все статические функции принимают структуру «instance» в качестве параметра, делают все, что нужно, и при необходимости возвращают результаты. Например, у вас может быть функция «GetPosition (CircleStruct obj)». Функция будет просто копаться в структуре, извлекать номера позиций, возможно строить новый объект PositionStruct, вставлять x и y в новый PositionStruct и возвращать его. GTK даже реализует наследование таким образом, внедряя структуры в структуры. довольно умно.

2 голосов
/ 10 сентября 2009

Первый компилятор c ++ фактически был препроцессором, который переводил код C ++ в C.

Так что очень возможно иметь классы на C. Вы можете попытаться найти старый препроцессор C ++ и посмотреть, какие решения он создает.

1 голос
/ 10 сентября 2009

Хотите виртуальные методы?

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

Если вы хотите использовать виртуальные методы, все становится сложнее. По сути, вам нужно реализовать свой собственный VTable для каждой структуры и назначить указатели функций для VTable в зависимости от того, какая функция вызывается. Затем вам потребуется набор указателей на функции в самой структуре, которые, в свою очередь, вызывают указатель на функцию в VTable. По сути, это то, что делает C ++.

TBH, хотя ... если вы хотите последнее, то вам, вероятно, лучше просто найти компилятор C ++, который вы можете использовать, и перекомпилировать проект. Я никогда не понимал навязчивую идею о том, что C ++ нельзя использовать во встроенных системах. Я использовал его много раз, и он работает быстро и не имеет проблем с памятью. Конечно, вы должны быть немного осторожнее с тем, что делаете, но на самом деле это не так сложно.

0 голосов
/ 10 сентября 2009

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

Кроме того, если вы можете использовать C, вы можете использовать C ++ и получать классы.

...