I am learning now some basic polymorphism in C. I try to write an constant element holding some method pointers that is gonna be inherited by higher level structures. When writing all my code in a single file it works fine, here is the desired behavior:
#include <stdio.h>
#include <string.h>
struct connection {
void (*connect)(struct connection self);
char name[16];
};
void connection_connect(struct connection self) {
printf("Connecting to %s\n", self.name);
}
const struct connection conn = {connection_connect};
typedef struct {
struct connection connection;
void (*setup)(char name[16]);
void (*connect)();
}__server;
__server server;
void server_setup(char name[16]) {
strcpy(server.connection.name, name);
}
void server_connect() {
server.connection.connect(server.connection);
}
__server server = {
conn, server_setup, server_connect
};
typedef struct {
struct connection connection;
void (*setup)(char name[16]);
void (*connect)();
}__client;
__client client;
void client_setup(char name[16]) {
strcpy(client.connection.name, name);
}
void client_connect() {
client.connection.connect(client.connection);
}
__client client = {
conn, client_setup, client_connect
};
int main(void) {
server.setup("Charlie");
client.setup("Delta");
server.connect();
client.connect();
return 0;
}
The problem occurs when moving all the structures to a different files. In this case I am forced to extern
the struct connection
constant object inside of my connection header file:
struct connection {
[...]
};
extern const struct connection conn_o;
And then define it in the .c source file:
[...]
const struct connection conn_o = {
connection_connect, connection_whereami
};
After that, when I try to assign the conn_o
to the static definition of server or client, I get an error saying that initializer element is not constant.
For example the initializer inside of server.c is handled like this:
__server server = {
conn_o, server_setup, server_connect
};
Is it possible to resolve this so conn_o
is constant after being initialized inside of connection.c
?
Thank you @Lundin for you comment.
I get to learn how little I have known about compiled languages. To hide the implementation details of a structure you will have to use pointer to on opaque structure hidden in .c file. This allow for compilation independence of this structure. To access opaque structure you can use only the API methods that you have defined inside of the header file (there is no way to deference such pointer to access it's instances). This technique is called Opaque Pointer, Pimpl Idiom, Bridge Pattern etc.
Wikipedia gives a good source of implementation in diverse languages