1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
|
#include <stdio.h>
typedef enum {
LoggerLevel_Error,
LoggerLevel_Warning,
LoggerLevel_Info,
LoggerLevel_Debug
} LoggerLevel;
// Classe de base (type parent) :
struct LoggerVTable;
typedef struct LoggerBase {
struct LoggerVTable* m_vtable; // pointeur vers la table virtuelle
} LoggerBase;
typedef struct LoggerVTable {
// Dans cet exemple, il n'y a qu'un seul pointeur de fonction.
// Mais, dans le cas général, une table virtuelle peut en avoir plusieurs.
void(*m_log)(LoggerBase* self, const char* msg, LoggerLevel level);
} LoggerVTable;
void LoggerLog(LoggerBase* self, const char* msg, LoggerLevel level) {
self->m_vtable->m_log(self, msg, level);
}
// Classe dérivée (sous-type) :
typedef struct LoggerDeriv {
LoggerBase super;
FILE* m_file;
} LoggerDeriv;
void LoggerDerivLog(LoggerDeriv* self, const char* msg, LoggerLevel level) {
fprintf(self->m_file, "%s\n", msg);
}
void LoggerDerivLogWithCast(LoggerBase* self, const char* msg, LoggerLevel level) {
LoggerDerivLog((LoggerDeriv*) self, msg, level);
}
LoggerVTable loggerDerivVTable = { &LoggerDerivLogWithCast };
void LoggerDerivCtor(LoggerDeriv* self, FILE* file) {
self->super.m_vtable = &loggerDerivVTable;
self->m_file = file;
}
// Démo :
int main() {
LoggerDeriv logger;
LoggerDerivCtor(&logger, stdout);
LoggerBase* loggerPtr = &logger.super;
// Code qui travaille avec un LoggerBase*, sans savoir que le type réel de l'objet est LoggerDeriv :
LoggerLog(loggerPtr, "Object oriented programming.", LoggerLevel_Debug);
return 0;
} |