4

假设我有一个void*包含指向 unknown 的指针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

3 回答 3

1

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

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

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

当你放弃一个 void 指针时,你是在对编译器说:“是的,你知道内存中的这个位置吗?好吧,将它用作这种类型”,如果内存无效,则调用 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
    }
}
于 2015-10-27T14:45:47.750 回答
0

据我了解,您需要一个多态对象,但没有通用基类。

已经有一个相当标准的成语 - 它被称为boost::any.

Aboost::any携带您的对象以及一些类型信息。该接口允许您查询类型并尝试将 any 转换为您要查找的类型。

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

于 2015-10-27T14:39:23.710 回答
0

为确保 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);
}
于 2015-10-27T14:24:07.283 回答