Do I set foo = NULL in INIT, then foo_init(foo) in create?
Yes. For robustness, you should also check in create() if foo is still NULL before allocating anything. Just to guard against create() being called twice on the same object.
Or should I just be doing the foo_init(foo) in INIT?
Generally, no. INIT should just set the storage to a consistent state.
And when freeing it later, should I be doing foo_destruct(foo) in EXIT or in destroy?
In EXIT.
Also, when using CMODs INHERIT, do INIT and EXIT get inherited as well, or just PIKEFUNs PIKEVARs and CVARs?
INIT and EXIT callbacks are inherited, otherwise things would break horribly if you inherit a C class from user Pike code.