Затраты C на classы

Отказ от ответственности: я полный новичок с C, но я играл с ним, пытаясь имитировать некоторые функции classов. Хорошо, я знаю, что если я хочу пойти таким путем, я должен изучить C ++, но рассмотрим следующий небольшой эксперимент .

Шрейнер, в книге Объектно-ориентированное программирование с ANSI-C предлагает способ использования указателей для получения объектов ориентации объектов в C. Я должен признать, что я только просматривал книгу, но мне не нравится его подход слишком много. В принципе, он использует указатели на функции, чтобы

func(foo); 

фактически приводит к вызову

 foo.methods->func(); 

где foo.methods – это структура, содержащая указатели на функции. То, что мне не нравится в этом подходе, состоит в том, что в любом случае нужно иметь глобальную функцию foo ; то есть методы не заменяются именами classа, в котором они живут. Я чувствую, что это скоро приведет к беспорядку: подумайте о двух объектах foo и bar , оба имеют метод func но с другим количеством параметров.

Поэтому я попытался получить что-то более подходящее на мой вкус. Первая попытка заключается в следующем (я пропущу декларации ради краткости)

 #include  //Instances of this struct will be my objects struct foo { //Properties int bar; //Methods void (* print)(struct foo self); void (* printSum)(struct foo self, int delta); }; //Here is the actual implementation of the methods static void printFoo(struct foo self) { printf("This is bar: %d\n", self.bar); } static void printSumFoo(struct foo self, int delta) { printf("This is bar plus delta: %d\n", self.bar + delta); } //This is a sort of constructor struct foo Foo(int bar) { struct foo foo = { .bar = bar, .print = &printFoo, .printSum = &printSumFoo }; return foo; } //Finally, this is how one calls the methods void main(void) { struct foo foo = Foo(14); foo.print(foo); // This is bar: 14 foo.printSum(foo, 2); // This is bar plus delta: 16 } 

Это неудобные, но вроде работы. Однако мне не нравится, что вы должны явно добавить сам объект в качестве первого аргумента. С некоторой работой препроцессора я могу сделать немного лучше:

 #include  #define __(stuff) stuff.method(* stuff.object) //Instances of this struct will be my objects struct foo { //Properties int bar; //Methods //Note: these are now struct themselves //and they contain a pointer the object... struct { void (* method)(struct foo self); struct foo * object; } print; }; //Here is the actual implementation of the methods static void printFoo(struct foo self) { printf("This is bar: %d\n", self.bar); } //This is a sort of constructor struct foo Foo(int bar) { struct foo foo = { .bar = bar, //...hence initialization is a little bit different .print = { .method = &printFoo, .object = &foo } }; return foo; } //Finally, this is how one calls the methods void main(void) { struct foo foo = Foo(14); //This is long and unconvenient... foo.print.method(* foo.print.object); // This is bar: 14 //...but it can be shortened by the preprocessor __(foo.print); // This is bar: 14 } 

Это насколько я могу получить. Проблема здесь в том, что она не будет работать для методов с аргументами, поскольку macros препроцессора не могут принимать переменное количество аргументов. Конечно, можно определить macros _0 , _1 и т. Д. В соответствии с количеством аргументов (до усталости), но это вряд ли хороший подход.

Есть ли способ улучшить это и позволить C использовать более объектно-ориентированный синтаксис?

Я должен добавить, что на самом деле Шрайнер делает гораздо больше, чем то, что я сказал в своей книге, но я думаю, что базовая конструкция не меняется.

Различные frameworks уже существуют. См. Например, http://ldeniau.web.cern.ch/ldeniau/html/oopc.html

Книга (в формате PDF), которая объясняет, как это сделать, является объектно-ориентированным программированием в ANSI C. Она старая (1993), но содержит некоторые действительные идеи и советы, IMHO.

Вы взглянули на Google Go? Это, в основном, модернизированный C, где делаются несколько, как вы предлагали. Он имеет параметрические polymorphismы. Поэтому вам не нужно это делать:

 static void printFoo(struct foo self) { printf("This is bar: %d\n", self.bar); } 

В Go это можно сделать следующим образом:

 static void print(Foo self) { printf("This is foo: %d\n", self.foo); } static void print(Bar self) { printf("This is bar: %d\n", self.bar); } 

В Go Foo и Bar также будут структуры. Таким образом, вы, в основном, являетесь разработчиком языка Go.

Обзор Go см. http://golang.org/doc/effective_go.html Это описание основного языка Go: http://golang.org/doc/effective_go.html