Моя программа должна использовать void * для переноса данных или объектов в динамическую ситуацию вызова, чтобы она могла ссылаться на данные произвольных типов, даже примитивных типы. Тем не менее, я недавно обнаружил, что процесс сбрасывания этих void * в случае классов с несколькими базовыми классами терпит неудачу и даже сбой моей программы после вызова методов на этих скрытых указателях, даже если адреса памяти кажутся правильными. Авария происходит во время доступа к «vtable».множественное наследование: неожиданный результат после отливки от void * до второго базового класса
Таким образом, я создал небольшой тестовый случай, среда GCC 4.2 на 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;
}
производит следующий вывод:
Decorated (direct)30,30
Shape 30,30
Square 30,30
Decorated (per void*) 73952,73952
DecoratedSquare 30,30
Как вы можете видеть, «декорирован (per void *) "результат совершенно неправильный. Он также должен быть 30,30, как в первой строке.
Независимо от метода литья, который я использую в shape_cast() Я всегда получаю такие же неожиданные результаты для Украшенной части. Что-то совершенно не так с этими пустотами *.
Из моего понимания C++ это должно быть действительно работающим. Есть ли шанс заставить это работать с void *? Может ли это быть ошибкой в gcc?
Благодаря
Вы можете использовать reinterpret_cast для приведения в действие void *, а затем вернуться к исходному типу. Вы можете __NOT__ отбрасывать на void *, а затем на что-нибудь еще. –
Вам будет намного лучше использовать шаблон декоратора, чем MI, а не тот, который разрешил бы литье из проблемы void *. – quamrana