C with classes is peak C for me. C++ is best when it is fixing C, not when it tries to be something else entirely.
(not my favorite)
struct foo;
struct foo *foo_alloc();
void foo_do_something(struct foo *p, ...);
This gives a simple to understand API with clearly defined boundary, has a stable ABI, preserves fast compilation times, avoids instruction bloat, etc. One could do this in C++ too, but what would be the point of using C++ then... struct private_impl_type;
std::unique_ptr<private_impl_type> impl;
If you choose this, you trade off optimization opportunities. Your choice.