dynamic_cast
используется для приведения полиморфного объекта к классу, который имеет тип объекта, который вы пытаетесь преобразовать, в качестве его родителя.
void*
полностью отличается от этого. с указателем на void вы буквально удаляете информацию о каждом типе.
dynamic_cast
знают, что есть базовый класс, и могут выполнять проверку типов через RTTI.
Когда вы сбрасываете пустой указатель, вы говорите компилятору: «Да, вы знаете это место в памяти? Ну, используйте его как этот тип», и если память недействительна, вызывается UB.
у вас есть три варианта здесь.
Вариант 1 Используйте интерфейс. Что ж, полиморфный базовый класс — единственный способ сделать dynamic_cast
. Другого пути нет, никаких хаков, это единственный путь. Просто как тот.
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived*>(base);
if (derived) {
// derived is valid here.
}
}
Вариант 2 Определите тип с помощью указателя. Я использую метод, чтобы иметь уникальный идентификатор для каждого типа и использовать идентификатор для проверки приведения. Сделано без RTTI
using type_id_t = void(*)();
template <typename T> void type_id() {}
// now we can use a map or a vector.
std::vector<std::pair<type_id_t, void*>> vec;
template<typename T>
void insertToMyVector(T* obj) {
vec.emplace_back(type_id<T>, obj);
}
template<typename T>
T* getObj(int index) {
auto item = vec[index];
return static_cast<T*>(item.first == &type_id<T> ? item.second : nullptr);
}
// ...
int main () {
auto foo = new Foo;
insertToMyVector(foo);
auto maybeFoo = getObj<Foo>(0);
if (maybeFoo) {
// you have a valid Foo here
}
}
Вариант 3. Создание производного класса для любого типа. Этот вариант весьма полезен, поскольку он может содержать любой тип, сохраняя при этом безопасность типов. Я похож на решение 1, но предлагаю больше гибкости. Хитрость заключается в создании производного класса для любого типа с использованием шаблонов. Преимущество в том, что вы можете держать любой тип, но это может немного усложнить вам обучение.
struct Base { virtual ~Base() = default; };
template<typename T>
struct Derived : Base {
Derived(T&& obj) : _obj{std::move(obj)} {}
Derived(const T& obj) : _obj{obj} {}
T& get() {
return _obj;
}
const T& get() const {
return _obj;
}
private:
T _obj;
};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived<int>*>(base);
if (derived) {
int i = derived->get();
// derived is valid here, and we can safely access the int
}
}
person
Guillaume Racicot
schedule
27.10.2015
java.lang.Object
является основой class для всего в Java. - person Jonathan Mee   schedule 27.10.2015dynamic_cast
работает только в том случае, если указатель действительно указывает на что-то, происходящее от этой базы; если вы хотите настаивать на этом, вы должны заставить свой интерфейс принимать указатели на базу, а не пустые указатели! - person   schedule 27.10.2015bar
, как вы можете гарантировать, что они происходят от определенного базового класса? - person James Adkison   schedule 27.10.2015bar
. И я не могу ничего гарантировать в отношении них, поэтому мне нуженdynamic_cast
для проверки типов во время выполнения. - person Jonathan Mee   schedule 27.10.2015void*
не находился под вашим контролем). Если вы контролируете точку вызова, то да, вы можете гарантировать, что используете оболочку. - person James Adkison   schedule 27.10.2015