Вы обычно делаете это с помощью указателей на функции.Другими словами, простые структуры, которые содержат как данные , так и , указывают на функции, которые манипулируют этими данными.Мы занимались такими вещами за годы до того, как на сцену вышел Bjarne S.
Так, например, в классе связи у вас будет вызов open, read, write и close, который будет поддерживаться равным четыремуказатели на функции в структуре, наряду с данными для объекта, что-то вроде:
typedef struct {
int (*open)(void *self, char *fspec);
int (*close)(void *self);
int (*read)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
int (*write)(void *self, void *buff, size_t max_sz, size_t *p_act_sz);
// And the data for the object goes here.
} tCommsClass;
tCommsClass commRs232;
commRs232.open = &rs232Open;
: :
commRs232.write = &rs232Write;
tCommsClass commTcp;
commTcp.open = &tcpOpen;
: :
commTcp.write = &tcpWrite;
Инициализация этих указателей на функции фактически будет в "конструкторе", таком как rs232Init(tCommClass*)
, который будет отвечать заустановка состояния по умолчанию этого конкретного объекта для соответствия определенному классу.
Когда вы «наследуете» от этого класса, вы просто меняете указатели, чтобы они указывали на ваши собственные функции.Каждый, кто вызывал эти функции, делал бы это через указатели на функции, давая вам ваш полиморфизм:
int stat = (commTcp.open)(commTcp, "bigiron.box.com:5000");
Вроде как настроенный вручную vtable , на языке C ++.
Вы могли бы даже иметь виртуальные классы, установив указатели на NULL - поведение будет немного отличаться от C ++, поскольку вы, вероятно, получите дамп ядра во время выполнения, а не ошибку во время компиляции.
Вотфрагмент примера кода, который демонстрирует это:
#include <stdio.h>
// The top-level class.
typedef struct _tCommClass {
int (*open)(struct _tCommClass *self, char *fspec);
} tCommClass;
// Function for the TCP class.
static int tcpOpen (tCommClass *tcp, char *fspec) {
printf ("Opening TCP: %s\n", fspec);
return 0;
}
static int tcpInit (tCommClass *tcp) {
tcp->open = &tcpOpen;
return 0;
}
// Function for the HTML class.
static int htmlOpen (tCommClass *html, char *fspec) {
printf ("Opening HTML: %s\n", fspec);
return 0;
}
static int htmlInit (tCommClass *html) {
html->open = &htmlOpen;
return 0;
}
// Test program.
int main (void) {
int status;
tCommClass commTcp, commHtml;
// Same base class but initialized to different sub-classes.
tcpInit (&commTcp);
htmlInit (&commHtml);
// Called in exactly the same manner.
status = (commTcp.open)(&commTcp, "bigiron.box.com:5000");
status = (commHtml.open)(&commHtml, "http://www.microsoft.com");
return 0;
}
Это приводит к выводу:
Opening TCP: bigiron.box.com:5000
Opening HTML: http://www.microsoft.com
, так что вы можете видеть, что различные функциив зависимости от подкласса.