Il mio programma deve utilizzare il void * per trasportare dati o oggetti in situazione di invocazione dinamica, in modo che possa fare riferimento a dati di tipi arbitrari, anche primitivi tipi. Tuttavia, ho scoperto di recente che il processo di down-casting di questi void * in caso di classi con più classi di base fallisce e addirittura causa l'arresto anomalo del mio programma dopo aver richiamato i metodi su questi puntatori downed cast anche se gli indirizzi di memoria sembrano essere corretti. L'arresto si verifica durante l'accesso a "vtable".ereditarietà multipla: risultato inatteso dopo il cast da void * a 2a classe base
Così ho creato un piccolo banco di prova, l'ambiente è gcc 4.2 su Mac OS X:
class Shape {
public:
virtual int w() = 0;
virtual int h() = 0;
};
class Square : public Shape {
public:
int l;
int w() {return l;}
int h() {return l;}
};
class Decorated {
public:
int padding;
int w() {return 2*padding;}
int h() {return 2*padding;}
};
class DecoratedSquare : public Square, public Decorated {
public:
int w() {return Square::w() + Decorated::w();}
int h() {return Square::h() + Decorated::h();}
};
#include <iostream>
template <class T> T shape_cast(void *vp) {
// return dynamic_cast<T>(vp); // not possible, no pointer to class type
// return static_cast<T>(vp);
// return T(vp);
// return (T)vp;
return reinterpret_cast<T>(vp);
}
int main(int argc, char *argv[]) {
DecoratedSquare *ds = new DecoratedSquare;
ds->l = 20;
ds->padding = 5;
void *dsvp = ds;
std::cout << "Decorated (direct)" << ds->w() << "," << ds->h() << std::endl;
std::cout << "Shape " << shape_cast<Shape*>(dsvp)->w() << "," << shape_cast<Shape*>(dsvp)->h() << std::endl;
std::cout << "Square " << shape_cast<Square*>(dsvp)->w() << "," << shape_cast<Square*>(dsvp)->h() << std::endl;
std::cout << "Decorated (per void*) " << shape_cast<Decorated*>(dsvp)->w() << "," << shape_cast<Decorated*>(dsvp)->h() << std::endl;
std::cout << "DecoratedSquare " << shape_cast<DecoratedSquare*>(dsvp)->w() << "," << shape_cast<DecoratedSquare*>(dsvp)->h() << std::endl;
}
produce il seguente output:
Decorated (direct)30,30
Shape 30,30
Square 30,30
Decorated (per void*) 73952,73952
DecoratedSquare 30,30
Come si può vedere, la "Decorato (per vuoto *) "il risultato è completamente sbagliato. Dovrebbe anche essere 30,30 come nella prima riga.
Qualunque metodo di cast che utilizzo in shape_cast() otterrò sempre gli stessi risultati imprevisti per la parte Decorated. C'è qualcosa di completamente sbagliato in questi vuoti *.
Dalla mia comprensione di C++ questo dovrebbe essere effettivamente funzionante. C'è qualche possibilità di farlo funzionare con il vuoto *? Può essere un bug in gcc?
Grazie
È possibile utilizzare reinterpret_cast per eseguire il cast a void * e quindi tornare al tipo originale. È possibile __NOT__ eseguire il cast a void * e quindi a qualsiasi altra cosa. –
Sarebbe molto meglio usare il pattern decoratore di MI, non che ciò risolva il cast dal problema void *. – quamrana