struct Adder;
struct Adder *adder_create(void);
void adder_setup(struct Adder *, int, int);
int adder_operate(struct Adder *);
void adder_delete(struct Adder *);
You can easily imagine how one would trivially implement these functions in adder.c, allocating an object, mutating its state and deleting it. The caller doesn't know anything about struct Adder nor does it know how the adding of two ints is implemented. It only needs know that struct Adder can be pointed to. The header file defines a clear interface that can be compiled against. The implementation can be changed without having to recompile all callers. Tried-and-true and boring but it works: this is the way C has done it for decades.Now, C++. You create a class Adder, declare public constructor and destructor as well as setup() and operate(). Then you declare a couple of private ints to hold state and maybe some private helper methods, and then you realise that 1) you've just exposed parts of the private implementation in the public header and 2) you can potentially break compiled binaries even if you only change the private/protected parts of the class. Yes, that's a textbook example of how to define a class that completely sucks for any real-life encapsulation purposes. You see how things are getting complex quick? This is where people began to think of more novel applications of C++ to fix the language itself.
So you define an abstract class IAdder in adder.h with pure virtual methods to act as a truly public interface, and derive an implementation class AdderImpl in adder.cpp. Great. Except you can't instantiate the private implementation. You'll need a public factory function outside the class or a static method such as IAdder::create() to construct an AdderImpl and return it as an IAdder. This isn't very clean and beautiful anymore and this was a simple example. There are more branches to be explored in the solution space but at this point we've basically had to create an ugly reimplementation of something that we thought would come free in a language that namely supports object oriented programming whose one fundamental selling point is easy encapsulation. And all that while the C counterpart is actually easy, understandable and simple, and requires no re-engineering to get it even work.