Проверка во время выполнения броска из пустоты *

Скажи, что у меня есть void* содержащий указатель на неизвестное class, Я хочу использовать dynamic_cast сделать проверку во время выполнения на тип класса, который я на самом деле. Например:

class Foo {};

void* bar = new Foo;

Если я попытаюсь сделать dynamic_cast<Foo*>(bar) Я получил:

‘void *’: недопустимый тип выражения для dynamic_cast

Однако я необходимость dynamic_cast потому что в моей реальной ситуации я не уверен, что bar на самом деле Foo*,

я прочел Вот что одним из решений этого является создание базового класса для всех объектов, которые bar может содержать, reinterpret_cast указатель на этот базовый класс, а затем попробуйте dynamic_cast от этого объекта указатель на Foo,

Это трудно для меня, потому что объекты, которые могут быть сохранены в bar не все под моим контролем. (И потому что попытка воссоздать Java вызывает у меня изжогу.) Есть ли другой способ сделать это?

4

Решение

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
}
}
1

Другие решения

Чтобы гарантировать, что dynamic_cast компилируется и работает, вы должны создать абстрактный или интерфейсный класс с виртуальным методом.

#include <cassert>

class Bar
{
public:
Bar() = default;
virtual ~Bar() = default;
};

class Foo : public Bar
{
public:
Foo() = default;
virtual ~Foo() = default;
};

int main()
{
Bar* bar = new Foo;
Foo* foo = dynamic_cast<Foo*>(bar);
assert(foo != nullptr);
}
0

Насколько я понимаю, вам нужен полиморфный объект, но нет общего базового класса.

Для этого уже существует довольно стандартная идиома — она ​​называется boost::any,

boost::any несет ваш объект плюс некоторую информацию о типе. Интерфейс позволяет вам запрашивать тип и пытаться привести любой тип к искомому типу.

http://www.boost.org/doc/libs/1_59_0/doc/html/any.html

0
По вопросам рекламы [email protected]