Here's a simple example. Suppose we define std::string with the following layout (for simplicity I'm removing the template stuff, SSO, etc.):
class string {
public:
// various methods here...
size_t size() const { return len_; }
private:
char *data_;
size_t len_;
size_t capacity_;
};
When a user calls .size() on a string, the compiler will emit some inlined instructions that access the len_ field at offset +8 bytes into the class (assuming 64-bit system).Now suppose we modify our implementation of std::string, and we want to change the order of the len_ and capacity_ fields, so the new order is: data_, capacity_, len_. If an executable or library links against the STL and isn't recompiled, it will have inlined instructions that are now reading the wrong field (capacity_).
This is what we mean by the C++ ABI. This is a simple example, but there are a lot of other changes that can break ABI this way.