#c #c #design-patterns
#c #c #шаблоны проектирования
Вопрос:
Я конвертирую кучу кода из C в C. Существует ли эквивалентный шаблон в C для фабрики объектов?
Рассмотрим следующий исходный код. На основе параметра int type
( ObjectFactory
) функция () должна возвращать указатель void на структуру типа pedicure . Как я могу создать экземпляр структуры таким образом, чтобы у меня был указатель на нее после возврата функции.
typedef struct {
unsigned int a;
unsigned int b;
unsigned int c;
} CThings ;
typedef struct {
unsigned int d;
unsigned int e;
unsigned int f;
} CPlaces ;
void * ObjectFactory( int type ) {
switch( type ) {
case 5 : {
return ??? CPlaces ;
break;
}
case 35 : {
return ??? CThings ;
break;
}
default: {
// unknown type
return NULL ;
}
}
return NULL ;
}
int _tmain(int argc, _TCHAR* argv[])
{
void * p = ObjectFactory( 5 );
// Do soemthing with the pointer.
CPlaces * places = (CPlaces*) p ;
places->d = 5 ;
places->e = 6 ;
places->f = 7 ;
return 0;
}
Комментарии:
1. Это, перевод C на C, на первый взгляд кажется особенно глупым упражнением. Не могли бы вы объяснить причины, по которым вы занимаетесь такой явно бессмысленной деятельностью?
2. @AlfP.Steinbach 1: Лучший комментарий, который вы когда-либо писали.
3. @Mooing Duck, ты не можешь этого сделать, как я уже говорил в своих вопросах, это C, а не C , и ключевое слово ‘new’ не существует.
4. Зачем вообще использовать этот термин
object
, если C является императивным языком программирования5. @Itsik: объектная ориентация не исключает императивного стиля в языке. C , конечно, не декларативный, хотя и объектно-ориентированный. (хотя вы, конечно, правы; в C нет объектов)
Ответ №1:
Как насчет использования malloc
:
case 5: return malloc(sizeof(struct CPlaces));
Нет необходимости в break
if, который вы уже возвращаете. Если хотите, вы можете добавить некоторую инициализацию перед возвратом.
Вызывающая сторона должна знать фактический тип, чтобы она могла привести указатель обратно к правильному типу. Вероятно, это будет равносильно дублированию инструкции switch на сайте вызывающего абонента.
Ответ №2:
#include <stdlib.h>
typedef enum enum_ObjectType {
CPlaces_Object = 5,
CThings_Object = 35,
} ObjectType;
typedef struct struct_CThings {
unsigned int a;
unsigned int b;
unsigned int c;
} CThings;
typedef struct struct_CPlaces {
unsigned int d;
unsigned int e;
unsigned int f;
} CPlaces ;
void *ObjectFactory(ObjectType type) {
switch( type ) {
case CPlaces_Object: {
return malloc(sizeof(CPlaces));
break;
}
case CThings_Object: {
return malloc(sizeof(CThings));
break;
}
default: { /* unknown type */
return NULL;
}
}
return NULL;
}
int main(void) {
CPlaces *places = ObjectFactory(CPlaces_Object);
CThings *things = ObjectFactory(CThings_Object);
things->a = 2;
things->b = 8;
things->c = 4;
places->d = 5;
places->e = 7;
places->f = 3;
return 0;
}
Комментарии:
1. К сожалению, это не совсем эквивалентно фабрике объектов C . Я бы ожидал, что мои объекты будут инициализированы чем-то другим, кроме мусора. Я бы предложил использовать параметр varargs, а также иметь функции «конструктора», которые переносят malloc и инициализацию. Эти конструкторы могут быть перегружены, чтобы принимать переменные и вызывать «настоящие» конструкторы после распаковки переменных.
2. Давайте, пожалуйста, не будем возиться с varargs. Если типы действительно связаны, и также разумно создать для них фабрику, тогда мы должны логически ожидать, что сможем построить любой из них с общим набором аргументов. Я имею в виду, что, используя varargs, нам в основном нужно знать, какой конструктор будет передан в любом случае, что, в свою очередь, означает, что мы должны знать, какой тип мы создаем, поэтому мы могли бы также создать его напрямую.
3. @Майкл Прайс, если вы не хотите, чтобы случайный мусор вызывал calloc вместо malloc; D
4. @Angelo’Sphere calloc по-прежнему не инициализирует мои «члены» так, как я хочу, чтобы они были. Если цель состоит в том, чтобы эмулировать объекты C на C, то это необходимо. ООП на C не является невозможным, просто он очень подробный.
5. @MichaelPrice Технически ничто не мешает вам указать функцию для инициализации структуры перед возвращением. Но, как вы сказали, реализация механизма классов на обычном C требует много тяжелой работы.