Прехвърляне на POD структура в производен тип

Докато работех върху наследен проектор, се натъкнах на следния модел: 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?


person Jens    schedule 13.05.2014    source източник
comment
и дори не е стандартно оформление в термините на C++11 А? Защо не? Доколкото виждам, и PODType, и DerivedFromPOD са POD в C++11.   -  person dyp    schedule 13.05.2014
comment
Начинът, по който дадена структура от данни е разположена в паметта, зависи от поведението на компилатора и ABI, стандартът не гарантира това. Мисля, че в този случай указател към непълен тип може да бъде по-изгоден. Също така не забравяйте, че преобразуването в стил C в C++ е наистина лошо нещо като цяло.   -  person user2485710    schedule 13.05.2014
comment
Това причинява недефинирано поведение според строгите правила за псевдоним.   -  person M.M    schedule 13.05.2014
comment
@dyp Misread раздел 9.7 има същия контрол на достъпа [...] за всички нестатични членове на данни. Ще редактирам публикацията.   -  person Jens    schedule 13.05.2014
comment
@dyp Но когато сега погледнах изходния код отново, разбрах, че съм пропуснал дефиницията на член (класът всъщност е доста голям), който със сигурност не е POD тип и следователно моят PODType също не е POD.   -  person Jens    schedule 13.05.2014
comment
Можете ли да промените DerivedFromPOD, за да имате PODType като член и след това да конструирате от PODType? Това би било много по-безопасно и не би трябвало да е толкова трудно.   -  person Rob K    schedule 13.05.2014
comment
Това е, което вече предложих, но не съм сигурен, че мога да го направя точно сега. Изходният код не принадлежи на нас, а на клиент и ние не трябва да променяме кода, без да имаме билет за грешка, свързан с него. Знам, че не е оптимално и има много повече проблеми в кода, но това е начинът, по който клиентът го иска.   -  person Jens    schedule 13.05.2014


Отговори (2)


Със сигурност не е гарантирано, че работи като цяло (опитайте да добавите виртуална функция към производния клас) и е формално недефинирано поведение. (Също така не виждам как struct може да се използва за подпомагане на прехвърлянето на данни по мрежата. Различните машини ще го представят по различен начин.)

person James Kanze    schedule 13.05.2014

DerivedFromPOD* указател може да бъде прехвърлен безопасно в PODType* указател. Така че сме сигурни, че оформлението на наследените PODType в паметта е същото.

Въпреки това, при кастинг в обратна посока, DerivedFromPOD може да се състави в паметта с някои данни на компилатора, след това данните PODType, след това някои допълнителни данни на компилатора.

Ако използвате C-style cast или static_cast<> за това cast, компилаторът ще приеме, че знаете какво правите и ще коригира адреса на показалеца, така че PODType частта от DerivedFromPOD да сочи правилно към добрата област.

Въпреки това не се опитвайте да използвате методи, които ще имат достъп до други данни от DerivedFromPOD, тъй като те няма да бъдат правилни в паметта.

По-специално, не използвайте никакви виртуални методи, тъй като VMT (Таблица с виртуални методи) не е там.

person Wizou    schedule 13.05.2014
comment
той кастира в обратната посока, от PODType към Derived. Освен това класът не е полиморфен, така че няма vtable. - person M.M; 13.05.2014
comment
Прочетете отговора ми внимателно. Започнах с начина, по който е безопасно, също и като отговор, свързан с въпроса му за оформлението в паметта. След това отговарям за PODType -› Произведен каст. Редът ми за виртуалния метод не е приложим тук, но исках да е пълен отговор. - person Wizou; 13.05.2014
comment
Не виждам къде отговаряте за каста на PODType-›Derived. Параграфи 1-3 говорят за Derived-›Pod, а параграф 4 е неясен. - person M.M; 13.05.2014