Вы можете добавить экспортируемые функции (импорт / экспорт declspec), не влияя на двоичную совместимость (гарантируя, что вы не удалите текущие функции и не добавите новые функции в конце), но вы не можете увеличить размер класса, добавляя новые данные члены.
Причина, по которой вы не можете увеличить размер класса, состоит в том, что для кого-то, кто скомпилировал, используя старый размер, но использует новый расширенный класс, это означало бы, что член данных, сохраненный после вашего класса в их объекте (и больше, если вы добавите больше, чем 1 слово) будет уничтожено к концу нового класса.
, например
Старый:
class CounterEngine {
public:
__declspec(dllexport) int getTotal();
private:
int iTotal; //4 bytes
};
Новое:
class CounterEngine {
public:
__declspec(dllexport) int getTotal();
__declspec(dllexport) int getMean();
private:
int iTotal; //4 bytes
int iMean; //4 bytes
};
Клиент тогда может иметь:
class ClientOfCounter {
public:
...
private:
CounterEngine iCounter;
int iBlah;
};
В памяти ClientOfCounter в старом фреймворке будет выглядеть примерно так:
ClientOfCounter: iCounter[offset 0],
iBlah[offset 4 bytes]
Тот же код (не перекомпилированный, но с использованием вашей новой версии будет выглядеть так)
ClientOfCounter: iCounter[offset 0],
iBlah[offset 4 bytes]
т.е.. он не знает, что iCounter теперь 8 байтов, а не 4 байта, поэтому iBlah фактически уничтожается последними 4 байтами iCounter.
Если у вас есть запасной элемент личных данных, вы можете добавить класс Body для хранения любых будущих элементов данных.
class CounterEngine {
public:
__declspec(dllexport) int getTotal();
private:
int iTotal; //4 bytes
void* iSpare; //future
};
class CounterEngineBody {
private:
int iMean; //4 bytes
void* iSpare[4]; //save space for future
};
class CounterEngine {
public:
__declspec(dllexport) int getTotal();
__declspec(dllexport) int getMean() { return iBody->iMean; }
private:
int iTotal; //4 bytes
CounterEngineBody* iBody; //now used to extend class with 'body' object
};