Разрешение того, что вы объявляете в качестве структуры действительно классом, обеспечивает безопасность типов при создании интерфейса C.
Вы можете заранее объявить свою структуру для интерфейса C:
struct Foo;
Вы можете объявить методы для него
void doStuffThatModifiesFoo( struct Foo * foo, ... );
struct Bar getStuffFromFoo( const struct Foo * foo );
Вы также можете написать для него методы create и destroy.
Ниже вы реализуете Foo не как структуру C, а как класс, а ваши клиенты C делают это.Не нужно это знать.Это лучше, чем передавать его как пустоту *, а затем разыгрывать (небезопасно, если кто-то передает вам пустоту * совершенно другому типу, а вы разыгрываете ее).