假设我有class
包含指向未知dynamic_cast
的指针。我想使用class Foo {};
void* bar = new Foo;
对我实际拥有的类的类型进行运行时检查。例如:
dynamic_cast<Foo*>(bar)
如果我尝试dynamic_cast
我得到:
'void *':dynamic_cast
的表达式类型无效
但我需要 bar
,因为在我的实际情况中,我不确定Foo*
实际上是bar
。
我已阅读Easiest way to get file ID from URL on Google Apps Script,其中一个解决方案是为reinterpret_cast
可包含的所有对象创建基类,为dynamic_cast
指向该基类的指针,然后尝试Foo
从该对象指针bar
。
这对我来说很难,因为可能存储在export DEBIAN_FRONTEND=noninteractive
apt-get update && apt-get upgrade -q -y --force-yes && apt-get dist-upgrade -q -y --force-yes
中的对象并非全部由我控制。 (并且试图重新创建Java让我感到胃灼热。)还有其他方法可以做到这一点吗?
答案 0 :(得分:1)
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 :(得分: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);
}
答案 2 :(得分:0)
据我所知,你想要一个多态对象,但没有共同的基类。
已经有一个相当标准的习惯用法 - 它被称为boost::any
。
boost::any
包含您的对象以及某些类型信息。界面允许您查询类型并尝试将any转换为您正在寻找的类型。