Работая над устаревшим проектором, я наткнулся на следующую схему:
структура POD используется для передачи данных по сети.
struct PODType {
// some data
int data;
};
На стороне получателя данные принимаются в объект типа POD. Позже, класс наследуется от PODType, а полученный объект преобразуется с приведением в стиле C в производный класс для использования некоторых методов, обращающихся к данным.
class DerivedFromPOD: public PODType {
public:
// some methods
int f(int x) {return data+x;}
protected:
// some methods
};
PODType pod;
receive(&pod);
DerivedFromPOD* d = (DerivedFromPOD*)&pod;
int i = d->f(10);
Производный класс имеет открытые и защищенные методы, поэтому он больше не является POD. Я знаю, что это злоупотребление наследованием, но оно уже давно в кодовой базе.
Мне интересно, гарантированно ли это будет работать со стандартной точки зрения (C ++ 03 или C ++ 98). Производный класс не имеет собственных членов данных или виртуальных функций, но я не уверен, гарантировал ли он, что схема памяти идентична, учитывая, что один является POD, а другой — нет. Вынужден ли компилятор размещать DerivedFromPOD таким образом, чтобы d.data
адрес совпадает с адресом объекта d типа DerivedFromPOD, как и для базового класса POD?
Это, безусловно, не гарантирует работу в целом (попробуйте добавить виртуальную функцию в производный класс), и это формально неопределенное поведение. (Я тоже не понимаю, как struct
может использоваться для передачи данных по сети. Разные машины будут представлять это по-разному.)
DerivedFromPOD*
Указатель можно безопасно привести в PODType*
указатель.
Таким образом, мы уверены, что макет наследственного PODType
в памяти то же самое.
Тем не менее, при приведении в противоположном направлении, DerivedFromPOD
может быть составлен в памяти с некоторыми данными компилятора, тогда PODType
данные, а затем некоторые дополнительные данные компилятора.
Если вы используете приведение в стиле C, или static_cast<>
для этого приведения компилятор предположит, что вы знаете, что вы делаете, и настроит адрес указателя так, чтобы PODType
часть DerivedFromPOD
правильно укажет на хороший район.
Однако не пытайтесь использовать методы, которые будут обращаться к другим данным из DerivedFromPOD
поскольку они не будут правильными в памяти.
В частности, не используйте виртуальные методы в качестве VMT (Таблица виртуальных методов) не там.