I believe your understanding is correct. Just changing the body of a member function doesn't change the amount of space required for an instance of that object. The code isn't stored "in" the object instance; only the data is.
When the class is compiled, references to member data fields are just offsets from the beginning of that object data. And derived classes' data are typically placed after the base class's data. So if you add a field to the base class, the correct offsets for the derived class data have all changed, which implies the base class needs recompiled, to point to the new (correct) offsets.
Before
class Foo {
int a; // offset 0 (assuming no vtable)
}
class Bar : public Foo {
int b; // offset 4
}
Bar bar; bar.b = 7; // sets the 32-bit value at this+4 to 7
After
class Foo {
int a; // offset 0
int c; // offset 4
}
class Bar : public Foo {
int b; // offset 8
}
Bar b; bar.b = 7; // Without recompiling: sets the 32-bit value at this+4
// which is actually where Foo.a is stored!
// With recompiling: sets the 32-bit value at this+8