Интерфейсные иерархии являются болью - они действительно "не наследовались" как таковой, так как у Вас может быть несколько "родителей" (из-за отсутствия лучшего термина).
"Выравнивание" (снова, не совсем правильное слово) иерархия могла бы включить проверку все интерфейсы что интерфейсные реализации и работающий оттуда...
interface ILow { void Low();}
interface IFoo : ILow { void Foo();}
interface IBar { void Bar();}
interface ITest : IFoo, IBar { void Test();}
static class Program
{
static void Main()
{
List<Type> considered = new List<Type>();
Queue<Type> queue = new Queue<Type>();
considered.Add(typeof(ITest));
queue.Enqueue(typeof(ITest));
while (queue.Count > 0)
{
Type type = queue.Dequeue();
Console.WriteLine("Considering " + type.Name);
foreach (Type tmp in type.GetInterfaces())
{
if (!considered.Contains(tmp))
{
considered.Add(tmp);
queue.Enqueue(tmp);
}
}
foreach (var member in type.GetMembers())
{
Console.WriteLine(member.Name);
}
}
}
}
Это зависит от того, какой именно «объектно-ориентированный» набор функций вы хотите иметь. Если вам нужны такие вещи, как перегрузка и / или виртуальные методы, вам, вероятно, потребуется включить указатели функций в структуры:
typedef struct {
float (*computeArea)(const ShapeClass *shape);
} ShapeClass;
float shape_computeArea(const ShapeClass *shape)
{
return shape->computeArea(shape);
}
Это позволит вам реализовать класс, «наследуя» базовый класс и реализуя подходящую функцию:
typedef struct {
ShapeClass shape;
float width, height;
} RectangleClass;
static float rectangle_computeArea(const ShapeClass *shape)
{
const RectangleClass *rect = (const RectangleClass *) shape;
return rect->width * rect->height;
}
Это, конечно, требует, чтобы вы также реализовали конструктор, который обеспечивает правильную настройку указателя функции. Обычно вы должны динамически выделять память для экземпляра, но вы также можете позволить вызывающей стороне сделать это:
void rectangle_new(RectangleClass *rect)
{
rect->width = rect->height = 0.f;
rect->shape.computeArea = rectangle_computeArea;
}
Если вам нужно несколько разных конструкторов, вам придется «украсить» имена функций, у вас не может быть больше, чем одна функция rectangle_new ()
:
void rectangle_new_with_lengths(RectangleClass *rect, float width, float height)
{
rectangle_new(rect);
rect->width = width;
rect->height = height;
}
Вот базовый пример, показывающий использование:
int main(void)
{
RectangleClass r1;
rectangle_new_with_lengths(&r1, 4.f, 5.f);
printf("rectangle r1's area is %f units square\n", shape_computeArea(&r1));
return 0;
}
Я надеюсь, что это даст вам некоторые идеи, как минимум. Для успешной и богатой объектно-ориентированной структуры на C, загляните в библиотеку glib GObject .
Также обратите внимание, что здесь не моделируется явный «класс», каждый объект имеет свои собственные указатели на методы, которые являются немного более гибким, чем вы обычно найдете в C ++. Кроме того, это стоит памяти. Вы могли бы уйти от этого, вставив указатели методов в структуру class
и изобрести способ для каждого экземпляра объекта ссылаться на класс.
Вам нужны виртуальные методы?
В противном случае вы просто определяете набор указателей на функции в самой структуре. Если вы назначите все указатели на функции стандартным функциям C, тогда вы сможете вызывать функции из C в синтаксисе, очень похожем на синтаксис C ++.
Если вы хотите иметь виртуальные методы, это становится более сложным. В основном вам нужно будет реализовать свой собственный VTable для каждой структуры и назначить указатели функций для VTable в зависимости от того, какая функция вызывается. Затем вам понадобится набор указателей на функции в самой структуре, которые, в свою очередь, вызывают указатель на функцию в VTable. По сути, это то, что делает C ++.
TBH ... если вам нужно последнее, то вам, вероятно, лучше просто найти компилятор C ++, который вы можете использовать, и перекомпилировать проект. Я никогда не понимал, что одержимость C ++ неприменима во встроенном. Я использовал его много раз, он работает быстро и не имеет проблем с памятью. Конечно, вы должны быть немного осторожнее в том, что делаете, но на самом деле это не так сложно.
C не является языком ООП, как вы правильно заметили, поэтому нет встроенного способа написать настоящий класс. Лучше всего взглянуть на структуры и указатели на функции , они позволят вам построить приближение класса. Однако, поскольку C является процедурным, вы можете подумать о написании большего количества C-подобного кода (т.е. без попытки использовать классы).
Кроме того, если вы можете использовать C, вы, вероятно, можете использовать C ++ и получить классы.
Первый компилятор C ++ на самом деле был препроцессором, который транслировал код C ++ в C.
Таким образом, очень возможно иметь классы в C. Вы можете попробовать откопать старый препроцессор C ++ и посмотреть, какие решения он создает.
Мой подход заключался бы в перемещении struct
и всех связанных в первую очередь функций в отдельный исходный файл (ы), чтобы что его можно использовать «переносимо».
В зависимости от вашего компилятора, вы могли иметь возможность включать функции в структуру
, но это очень специфичное для компилятора расширение и не имеет ничего общего с последней версией стандарта, который я обычно использовал :)
См. Также этот ответ и этот
Это возможно. В то время это всегда кажется хорошей идеей, но потом становится кошмаром для обслуживания. Ваш код становится завален кусками кода, связывающими все вместе. У нового программиста будет много проблем с чтением и пониманием кода, если вы используете указатели на функции, поскольку не будет очевидно, какие функции вызываются.
Скрытие данных с помощью функций get / set легко реализовать в C, но остановимся на этом. Я видел несколько попыток сделать это во встроенной среде, и в конце концов это всегда проблема обслуживания.
Поскольку у всех вас есть проблемы с обслуживанием, я бы держался подальше.
В вашем случае хорошим приближением класса может быть ADT . Но все равно не будет.
Невозможно, чтобы слияние (или перебазирование) могло работать без касания рабочего каталога (и индекса), поскольку могут возникнуть конфликты слияния, которые необходимо разрешить с помощью рабочего каталога (и / или index).
У вас всегда может быть другой клон (возможно, используя альтернативы или каталог объектов с символическими ссылками для экономии места на диске) или другой рабочий каталог с contrib / workdir / git-new-workdir
. Или используйте такой инструмент, как ccache .
Изменить: в настоящее время git worktree
является частью ядра Git, нет необходимости во внешних инструментах (по крайней мере, с git версии 2.6 .0).
Интерфейсы и реализации C: методы создания программного обеспечения многократного использования , Дэвид Р. Хэнсон
http://www.informit.com/store/product.aspx? isbn = 0201498413
Эта книга отлично справляется с ответом на ваш вопрос. Это из серии профессиональных вычислений Аддисона Уэсли.
Основная парадигма выглядит примерно так:
/* for data structure foo */
FOO *myfoo;
myfoo = foo_create(...);
foo_something(myfoo, ...);
myfoo = foo_append(myfoo, ...);
foo_delete(myfoo);
Используйте структуру
для имитации элементов данных класса. Что касается области действия метода, вы можете имитировать частные методы, поместив прототипы частных функций в файл .c и общедоступных функций в файл .h.
вы можете взглянуть на GOBject. это библиотека ОС, которая дает вам подробный способ создания объекта.
Если вам нужен только один класс, используйте массив struct
s в качестве данных "объектов" и передать указатели на них функциям-членам. Вы можете использовать typedef struct _whatever Whatever
перед объявлением struct _whatever
, чтобы скрыть реализацию от клиентского кода. Нет никакой разницы между таким «объектом» и объектом стандартной библиотеки C. FILE
.
Если вам нужно несколько классов с наследованием и виртуальными функциями, то обычно указатели на функции являются членами структуры или общий указатель на таблицу виртуальных функций. Библиотека GObject использует как этот прием, так и трюк с определением типов, и широко используется.
Вот ' Кроме того, в Интернете доступна книга по методам этого решения - Объектно-ориентированное программирование с использованием ANSI C .
Мне тоже однажды пришлось сделать это в качестве домашней работы. Я использовал следующий подход:
Простым примером может быть следующее:
/// Queue.h
struct Queue
{
/// members
}
typedef struct Queue Queue;
void push(Queue* q, int element);
void pop(Queue* q);
// etc.
///