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

时间:2011-06-30 23:19:35

标签: c++ arrays pointers type-safety dynamic-cast

我正在尝试确定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<Object*>Array<String*>,我想通过动态保证最小的类型安全性在每个元素访问时键入check,例如:

#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<Object*>的情况下失败,但我不确定是否可以插入非 - 在不使用reinterpret_cast的情况下将对象转换为Array<Object*>

4 个答案:

答案 0 :(得分:1)

根据你的例子,听起来你有一些浅拷贝数组,有人可以欺骗它们包含不同于它们应该包含的类型。我认为这个问题的“正常”解决方案是让用户难以做到(即不提供Array<T>Array<U>之间的转换)。但是,如果你对自己的想法感兴趣,我认为这样可行:

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的子类(具体如何是一个完全不同的主题)。一旦完成,请向下转换为Object *,然后使用dynamic_cast备份到Subclass,这样可以实现目标。

答案 1 :(得分:1)

让我看看我是否关注你的需求,并在此过程中提出一些建议......

Array<String*> v(10);

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

Array<Object*> o = v;

创建一个v.size() / 10 Object*个数组,每个数组都来自String*s中的v

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()没有先失败,并且异常是你故意测试的元素类型满足期望:如果你使用代理对象,那么这里没有问题阻止整数进入Array<Object*>

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

同样,我猜这应该失败,因为你之前的Integer任务没有,而且这里没有新问题。

cout << str << endl;

因此,代理对象似乎很关键。如果你不知道如何写一个,请告诉我,但我猜你做了....

答案 2 :(得分:0)

来自同一类型的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;
}

答案 3 :(得分:0)

简单介绍一个带有虚析构函数的公共基类。使用空基优化,这可能不会增加任何开销,并且会使dynamic_cast正常工作。