>>66
// T.h
struct T;
T* new_T(...);
void delete_T(T* this);
void T_dosomething(struct T* this);

// T.c
#include "T.h"
struct T
{
 ...
};
T* new_T(...) { T* this = (T*)malloc(sizeof(T)); ...; return this; }
void delete_T(T* this) { if(this) { ...; free(this); } }
void T_dosomething(struct T* this) { ... }

こうすると、Tのメンバを変更しても使用側の再コンパイルがかからなくてウマー。
ほぼ完全な private を実現できる。
仮想関数も T.c の都合で決めればいい。

ただしデメリットもある。
・生成にはほぼメモリの動的確保が必須、
・T.c にすべての実装をまとめなくてはならない