Просто для полноты (зная, что я немного опаздываю, только для опоздавших читателей, таких как я ...):
static_cast
может применяться , если используется правильно!
Сначала простой случай:
struct D1 { }; // note: no common base class B!
struct D2 { };
struct DD : D1, D2 { };
Вы можете получить от D1*
до D2*
через промежуточное понижение до DD*
:
D1* d1 = new DD();
D2* d2 = static_cast<DD*>(d1);
Переход к D2 * неявен. Это возможно даже для не виртуального наследования. Но имейте в виду, что вам нужно быть 100% уверенным, что d1 действительно был создан как DD
при выполнении отката, в противном случае вы окажетесь в неопределенном поведении!
Теперь более сложный случай: ромбовидный рисунок! Вот что представлено в вопросе:
void* cptr = new DD();
B* a = (B*)cptr;
Теперь этот состав уже опасен! На самом деле здесь реализовано reinterpret_cast:
B* a = reinterpret_cast<B*>(cptr);
То, что вы взамен хотите, - это простой отклик. Как правило, не нужно вообще использовать приведение:
B* a = new DD(); //ambigous!
Исключительно: DD имеет два унаследованных экземпляра B. Это сработало бы, если бы D1 и D2 унаследовали виртуально от B (struct D1/2 : virtual B { };
- не следует путать с B / D1 / D2, являющимся виртуальным классы!).
B* b1 = static_cast<D1*>(new DD());
B* b2 = static_cast<D2*>(new DD());
Приведение к соответствующим базам D1
или D2
теперь проясняет, на какой из двух унаследованных экземпляров B
следует указать.
Теперь вы можете вернуть соответствующий другой экземпляр, снова понижая до DD; из-за ромбовидного рисунка вам снова понадобится промежуточный состав:
D2* bb1 = static_cast<DD*>(static_cast<D1*>(b1));
D1* bb2 = static_cast<DD*>(static_cast<D2*>(b2));
Очень важный момент во всем этом вопросе: вам абсолютно необходимо использовать при низком литье тот же алмазный край, который вы использовали для повышающего литья !!!
Вывод: Да, возможно возможно с использованием статических приведений, и это единственный вариант, если участвующие классы не являются виртуальными (примечание: отличаться от виртуального наследования!). Но просто слишком легко ошибиться, иногда даже невозможно (например, если хранить указатели базового типа на произвольные производные типы в std::vector
), как правило, решение dynamic_cast
Ben является намного более безопасным (при условии, что доступны виртуальные типы данных; если это так, то в приведенном выше примере с вектором это решение only ! ).