с++: указать для класса интерфейс с методами так, чтобы не менять размера объекта класса
подскажите, можно ли реализовать следующую идею:
есть интерфейс
class IBase {
public:
virtual operator CData() const = 0;
}
есть соответствующий класс
class CChild : public IBase {
public:
operator CData() const;
public:
int m_data;
}
изначально (когда не было базового класса) через CChild считывались данные из файла (записанные в бинарном виде, т.е. блоками по sizeof(CChild))
но затем, когда был введен базовый класс это стало невозможным, поскольку virtual увеличивает размер объекта на размер указателя (8байт для 64битной сборки)
такой вопрос - как обойти данную проблему
понятно, что можно
отказаться от наследования, но очень было хотелось показать, что у
CChildобязательно должен быть методoperator CData() const;(ну отчасти из-за эстетических соображений, отчасти из-за того, что таких классовCChildXнесколько и у каждого своя начинка, свои размеры, но у всех есть один и тот же обязательный метод)не делать наследование от абстрактного класса (чтобы не было
virtualметодов), но тогда возникают проблемы с универсализацией использования :(
Подскажите как обычно выходят из данной проблемы?
Ответы (3 шт):
Наследование убрать, а наличие (и правильность сигнатуры) метода проверять концептом, или, до C++20, SFINAE.
class CData{
};
class IBase {
public:
virtual operator CData() const = 0;
};
class CChild {
public:
operator CData() const;
public:
int m_data;
};
class VCChild1 : public IBase , public CChild {
public:
virtual operator CData() const {return CChild::operator CData();}
};
// или так
class VCChild2 : public IBase {
public :
CChild c ;
virtual operator CData() const {return CData(c);}
};
В файл записывать статический элемент объекта static_cast<CChild&> или CChild c ;. А экземпляр с виртуальными функциями из класса VCChild будет работать.
Из данной проблемы выходят сериализацией. Не нужно опираться на бинарное представление экземпляра класса в памяти для его хранения на диске. Даже в случае Plain Old Data (без виртуальности, наследования и разных модификаторов доступа) могут играть роль выравнивания, да и просто размеры конкретных полей данных (sizeof(int) может разниться от системы к системе). Поэтому, чтобы сохранять и в последствии загружать (заполнять) объекты надо использовать сериализацию. В текущем виде вопрос выглядит как ошибка молотка.