来自 void 的 Cast 的运行时检查* [英] Run-Time Checking of a Cast from a void*

查看:66
本文介绍了来自 void 的 Cast 的运行时检查*的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

class Foo {};void* bar = new Foo;

如果我尝试执行 dynamic_cast(bar) 我得到:

<块引用>

'void *':dynamic_cast 的表达式类型无效

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

我已在此处阅读到此问题的一种解决方案是为的所有对象创建一个基类bar 可以包含,reinterpret_cast 指向该基类的指针,然后尝试从该对象指针dynamic_castFoo.

这对我来说很困难,因为可能存储在 bar 中的对象并非都在我的控制之下.(因为尝试重新创建 Java 让我感到心痛.)还有其他方法可以做到这一点吗?

解决方案

dynamic_cast 用于将多态对象转换为具有您尝试转换为的对象类型的类它是父母.

void* 与此完全不同.使用指向 void 的指针,您实际上是在剥离所有类型信息.

dynamic_cast 知道有一个基类,可以通过 RTTI 进行类型检查.

当你抛出一个空指针时,你是在对编译器说:是的,你知道内存中的这个地方?好吧,将它用作这种类型",如果内存无效,则调用 UB.

这里有三个选择.

选项 1使用接口.好吧,多态基类是执行dynamic_cast 的唯一方法.没有其他方法,没有黑客,这是唯一的方法.就这么简单.

struct Base { virtual ~Base() = default;};结构派生:基{};//...无效测试(基础*基础){自动派生 = dynamic_cast(base);如果(派生){//派生在这里是有效的.}}

选项 2用指针标识类型我使用一种方法为每种类型设置一个唯一标识符,并使用该标识符来验证强制转换.在没有任何 RTTI 的情况下完成

使用 type_id_t = void(*)();模板 void type_id() {}//现在我们可以使用地图或向量.std::vector>vec;模板void insertToMyVector(T* obj) {vec.emplace_back(type_id, obj);}模板T* getObj(int index) {自动项目 = vec[index];return static_cast(item.first == &type_id ? item.second : nullptr);}//...int主(){自动 foo = 新 Foo;insertToMyVector(foo);auto mayFoo = getObj(0);如果(maybeFoo){//你在这里有一个有效的 Foo}}

选项 3为任何类型生成派生类这个非常有用,因为它可以保存任何类型,同时保持类型安全.我看起来像解决方案 1,但提供了更大的灵活性.使用模板为任何类型生成派生类的技巧.优点是你可以持有任何类型,但可能会让你有点复杂.

struct Base { virtual ~Base() = default;};模板结构派生:基{派生(T&& obj) : _obj{std::move(obj)} {}派生(const T& obj):_obj{obj} {}夯;得到() {返回_obj;}const T&获取()常量{返回_obj;}私人的:T_obj;};//...无效测试(基础*基础){自动派生 = dynamic_cast<Derived<int>*>(base);如果(派生){int i = 派生->get();//派生在这里是有效的,我们可以安全地访问 int}}

Say that I have a void* containing a pointer to an unknown class. I want to use dynamic_cast to do run-time checking on the type of class I actually have. For example:

class Foo {};

void* bar = new Foo;

If I attempt to do dynamic_cast<Foo*>(bar) I get:

'void *': invalid expression type for dynamic_cast

However I need dynamic_cast because in my actual situation I'm not sure that bar is in fact a Foo*.

I've read here that one solution to this is to create a base class for all objects that bar could contain, reinterpret_cast to a pointer to that base class, and then try to dynamic_cast from that object pointer to Foo.

This is difficult for me because the objects that may be stored in bar are not all under my control. (And cause trying to recreate Java gives me heartburn.) Is there another way to do this?

解决方案

dynamic_cast is use to cast down a polymorphic object to a class that has the type of the object you're trying to cast as it's parent.

void* is completely different from that. with a pointer to void, you are literally stripping every type information away.

dynamic_cast know that there's a base class and can do type checking through RTTI.

When you cast down a void pointer, you're saying to the compiler: "yeah you know this place in the memory? well, use it as this type" and if the memory is invalid, UB is invoked.

you have three choices here.

Option 1 Use an interface. Well, a polymorphic base class is the only way to do a dynamic_cast. There is no other way, no hacks, it's the only way. Simple as that.

struct Base { virtual ~Base() = default; };

struct Derived : Base {};

// ...

void test (Base* base) {
    auto derived = dynamic_cast<Derived*>(base);

    if (derived) {
        // derived is valid here.
    }
}

Option 2 Identify the type with the pointer I use a method to have a unique identifier per type and use the identifier to validate the cast. Done without any 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
    }
}

Option 3 Generate derived class for any type This one is quite useful as it can hold any type while keeping type safety. I look like solution 1 but offer more flexibility. The trick it to generate a derived class for any type using templates. The advantage is you can hold any type, but may complexify you cade a bit.

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

这篇关于来自 void 的 Cast 的运行时检查*的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆