Dynamic_cast 到相同类型不检查对象的类型

发布于 2024-11-18 03:09:56 字数 1136 浏览 4 评论 0原文

我试图确定 T* 指针指向的对象是否真正是 T 对象,还是其他一些不相关的类型。我尝试了dynamic_cast,但是它并没有什么用,它返回指针本身而不是null,即使很明显它没有指向有效的T对象:

Object* garbage = reinterpret_cast<Object*>(0x12345678);
if( dynamic_cast<Object*>(garbage) == NULL ){
    cout << "Expected behaviour (by me)" << endl;
}else{
    cout << "You've got to be kidding me" << endl;
}

是否有任何解决方法,或者其他解决方案?我尝试在dynamic_cast之前强制转换为void*和char*,但没有效果,typeid也不够,因为我也想接受子类。

一些上下文:我正在编写一个自定义数组类,实现不同类型数组之间的浅层转换,例如 Array和 Array,以及我想通过在每个元素访问时进行动态类型检查来保证最低的类型安全性,例如:

#define DEBUG
Array<String*> v(10);
Array<Object*> o = v;
o[0] = new Integer(1);      //  this is technically illegal but no idea how to check
//Array<String*> w = o;     //  this fails with an exception
String* str = v[0];         //  but this should fail horribly as well
cout << str << endl;

转换为 Object*,然后对 Object* 进行类型检查在很多情况下都有效,但在这种情况下会失败的Array,尽管我不确定是否可以在不使用reinterpret_cast的情况下将非对象插入到Array中。

I am trying to determine whether an object pointed by a T* pointer is truly a T object, or some other, unrelated type. I tried dynamic_cast, however it is less than useless, it returns the pointer itself instead of null even when it is obvious it does not point to a valid T object:

Object* garbage = reinterpret_cast<Object*>(0x12345678);
if( dynamic_cast<Object*>(garbage) == NULL ){
    cout << "Expected behaviour (by me)" << endl;
}else{
    cout << "You've got to be kidding me" << endl;
}

Is there any workaround for this, or some other solution? I've tried casting to void* and char* before the dynamic_cast to no avail, typeid is not enough either since I want to accept subclasses as well.

Some context: I'm writing a custom Array class implementing shallow conversion between different kinds of Arrays, like Array<Object*> and Array<String*>, and I would like to guarantee a minimal type safety by doing a dynamic type check at every element access, for example:

#define DEBUG
Array<String*> v(10);
Array<Object*> o = v;
o[0] = new Integer(1);      //  this is technically illegal but no idea how to check
//Array<String*> w = o;     //  this fails with an exception
String* str = v[0];         //  but this should fail horribly as well
cout << str << endl;

Casting to Object*, then doing the type check on the Object* works in a lot of cases, but it fails in the case of Array<Object*>, though I am not sure whether it is possible to insert something non-Object into an Array<Object*> without the use of reinterpret_cast.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

失与倦" 2024-11-25 03:09:56

根据您的示例,听起来您有浅复制数组,有人可能会欺骗其中包含与应包含的类型不同的类型。我认为这个问题的“正常”解决方案是让用户很难做到这一点(即不提供 Array和 Array 之间的转换) >)。但是,如果您坚定自己的想法,我认为这会起作用:

template<typename Subclass>
class Array {
public:
    // ...
    Subclass *operator [] (size_t index) {
        assert( index < size_ );
        assert( dynamic_cast<Subclass*>(static_cast<Object*>(internal_[index])) != NULL );
        // ...
    }
    // ...
private:
    size_t size_;
    Subclass **internal_;
};

您可以执行一些模板元魔法和静态断言,以确保 Subclass 确实是 Object< 的子类/code> (具体如何是一个完全不同的主题)。一旦解决了这个问题,向下转换为 Object*,然后使用dynamic_cast 返回到 Subclass 应该可以实现您的目标。

Base on your example, it sounds like you've got shallow copy Arrays which someone could trick into containing different types than they are supposed to contain. I think the "normal" solution to this problem would be to make that difficult for users to do (i.e. don't provide conversions between Array<T> and Array<U>). But, if you're set in your ideas I think this will work:

template<typename Subclass>
class Array {
public:
    // ...
    Subclass *operator [] (size_t index) {
        assert( index < size_ );
        assert( dynamic_cast<Subclass*>(static_cast<Object*>(internal_[index])) != NULL );
        // ...
    }
    // ...
private:
    size_t size_;
    Subclass **internal_;
};

You can do some template meta-magic and a static assert to make sure that Subclass is really a Subclass of Object (exactly how is a completely different topic). Once that is out of the way, casting down to an Object* and then back up to Subclass with a dynamic_cast should accomplish your goal.

剑心龙吟 2024-11-25 03:09:56

让我看看我是否满足您的需求,并提出一些建议...

Array<String*> v(10);

似乎这是为了给您一个包含 10 个 String* 并初始化为 NULL/0 的数组。

Array<Object*> o = v;

创建一个由 v.size() / 10 个 Object* 组成的数组,每个都从 v 中的 String*s 复制而来代码>.

o[0] = new Integer(1); //  technically illegal but no idea how to check

如果这是非法的,那么您显然希望防止覆盖 Object* ,从而更改运行时类型...

  • 您需要拦截 operator= 来实现 拦截 operator=之前/之后的类型比较
  • ,需要 o[0] 返回一个可以指定 operator= 的类型
    • o[0] 返回一个 Object* 永远不会起作用,因为指针不是用户定义的类:您无法修改 operator= 行为< /里>
    • 你必须让 o[0] 返回一个代理对象 - 这里几乎是一个迭代器,尽管语义和赋值类型断言与标准容器迭代器不同

这给我们带来了:

Array<String*> w = o;     //  this fails with an exception

我认为这只是失败,因为你的 o[0] = new Integer() 上面首先并没有失败,例外是您故意测试元素类型是否满足预期:如果您使用所讨论的代理对象来阻止 Integer 进入 Array< /代码>。

String* str = v[0];     //  should fail horribly as well

同样,我猜测这应该会失败,因为您之前的 Integer 分配没有失败,并且这里没有新问题。

cout << str << endl;

所以,代理对象似乎很关键。如果您不知道如何写,请告诉我,但我猜您知道......

Let me see if I'm following your needs, and makes some suggestions along the way...

Array<String*> v(10);

Seems this is meant to give you an array with 10 String*s initialised to NULL/0.

Array<Object*> o = v;

Creates an array of v.size() / 10 Object*s, each copied from the String*s in v.

o[0] = new Integer(1); //  technically illegal but no idea how to check

If this is illegal, then you obvious want to prevent overwriting of Object*s where that changes the run-time type...

  • you need to intercept the operator= to implement the before/after type comparison
  • to intercept operator=, you need o[0] to return a type whose operator= you can specify
    • letting o[0] return an Object* will never work, as pointers aren't user-defined classes: you can't modify the operator= behaviour
    • you must have o[0] return a proxy object - here pretty much an iterator though the semantics and assignment type assertion is different from Standard container iterators

Which brings us to:

Array<String*> w = o;     //  this fails with an exception

I assume this is only failing because your o[0] = new Integer() above wasn't failing first, and that the exception is your deliberate test that the element types meet expectations: no problem here then if you use a proxy object as discussed to stop the Integer getting into the Array<Object*>.

String* str = v[0];     //  should fail horribly as well

Again, I'm guessing this should fail because your earlier Integer assignment didn't, and there's no new problem here.

cout << str << endl;

So, the proxy object seems key. Let me know if you don't know how to write one, but I'm guessing you do....

海夕 2024-11-25 03:09:56

来自和到相同类型的 dynamic_cast 在 C++ 中被定义为无操作,因此它不会在您的示例中“失败”。您可以改用 typeid 运算符。

例如,这个程序很可能崩溃(这是从随机地址的对象获取类型信息的“预期”结果):

int main()
{
    Object* garbage = reinterpret_cast<Object*>(0x12345678);
    if (typeid(*garbage) == typeid(Object))
        cout << "Your program thinks this garbage is an actual object!" << std::endl;
}

A dynamic_cast from and to the same type is defined as a no-op in C++, so it cannot "fail" with your example. You can use the typeid operator instead.

For instance, this program is very likely to crash (which is the "expected" result for getting type information from an object at a random address):

int main()
{
    Object* garbage = reinterpret_cast<Object*>(0x12345678);
    if (typeid(*garbage) == typeid(Object))
        cout << "Your program thinks this garbage is an actual object!" << std::endl;
}
草莓味的萝莉 2024-11-25 03:09:56

只需引入一个带有虚拟析构函数的公共基类即可。通过空基优化,这可能不会增加任何开销,并且会使 dynamic_cast 正常工作。

Just introduce a common base class with a virtual destructor. With the empty-base optimization, this probably won't add any overhead, and it will make dynamic_cast just work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文