c – 从空白中进行演员的运行时检查*

假设我有一个包含指向未知类的指针的void *.我想使用dynamic_cast对我实际拥有的类的类型进行运行时检查.例如:

class Foo {};

void* bar = new Foo;

如果我尝试做dynamic_cast< Foo *>(bar),我得到:

‘void *’: invalid expression type for dynamic_cast

但是我需要dynamic_cast,因为在我的实际情况中,我不确定bar实际上是Foo *.

我已经阅读了here,其中一个解决方案是为bar可以包含的所有对象创建一个基类,将reinterpret_cast重新指定为指向该基类的指针,然后尝试从该对象指向dynamic_cast到Foo.

这对我来说很难,因为可能存储在栏中的对象并非都在我的控制之下. (并且导致尝试重新创建Java让我心痛.)还有另一种方法吗?

最佳答案 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
    }
}
点赞