C++ 对同一类型的动态\u转换不会检查对象的类型

C++ 对同一类型的动态\u转换不会检查对象的类型,c++,arrays,pointers,type-safety,dynamic-cast,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

我试图确定由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;
}
Object*garbage=reinterpret\u cast(0x12345678);
if(动态_转换(垃圾)==NULL){

CUT<代码>动态>强制> <代码>定义为C++中的NOP,因此它不能“失败”,可以使用<代码> Type ID > /Cux>运算符。 例如,此程序很可能崩溃(这是从随机地址的对象获取类型信息的“预期”结果):

intmain()
{
Object*garbage=reinterpret_cast(0x12345678);
if(typeid(*垃圾)=typeid(对象))

不能只引入一个带有虚拟析构函数的公共基类。使用空基类优化,这可能不会增加任何开销,而且会使
dynamic\u cast
正常工作。

基于您的示例,听起来您有一些浅拷贝数组,有人可以诱使它们包含不同于支持的类型我认为这个问题的“正常”解决方案是让用户很难做到这一点(即不提供
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_;
};
模板
类数组{
公众:
// ...
子类*运算符[](大小索引){
断言(索引<大小));
断言(动态转换(静态转换(内部索引))!=NULL;
// ...
}
// ...
私人:
大小\u t大小\u;
子类**内部;
};

您可以执行一些模板元魔术和静态断言,以确保
子类
确实是
对象
的子类(完全不同的主题是什么)。一旦解决了这个问题,向下转换到一个对象*然后使用动态转换返回到
子类应该可以实现您的目标。

让我看看我是否遵循了您的需求,并在此过程中提出一些建议

Array<String*> v(10);
创建一个
v.size()
/10
对象*
s的数组,每个数组都是从
v
中的
字符串*s
复制的

o[0] = new Integer(1); //  technically illegal but no idea how to check
如果这是非法的,那么您显然希望防止覆盖
对象*
s,从而更改运行时类型

  • 您需要截取
    运算符=
    ,以实现前后类型比较
  • 要截取
    operator=
    ,需要
    o[0]
    返回一个类型,您可以指定该类型的
    operator=
    • o[0]
      返回一个对象*永远不会起作用,因为指针不是用户定义的类:您不能修改
      操作符=
      的行为
    • 您必须让o[0]返回一个代理对象——这里几乎是一个迭代器,尽管语义和赋值类型断言不同于标准容器迭代器
这让我们想到:

Array<String*> w = o;     //  this fails with an exception
同样,我猜这应该会失败,因为您之前的
Integer
赋值没有成功,而且这里没有新问题

cout << str << endl;

是否仍有可能出现误报。对于的子类,这将失败Object@BenVoigt,关于type_info或崩溃的比较?@zneak:使用任意指针调用
typeid
是未定义的行为,它可能意外返回
typeid(对象)
@Frigo,没有与指针关联的RTTI。您无法在运行时检查指针的类型,只能检查对象的类型。什么是
String
Object
Integer
?为什么
String*str=v[0];
行失败?
v[0]
是一个
字符串*
,因此副本是完全有效的。我在代码中做了一些澄清。Object是字符串和Integer的(公共的,非虚拟的)基,它们都是多态的,至少有一个虚拟析构函数。Object从NonCopyable私有派生;String和Integer从一些“接口”,但我怀疑这是否起作用。当我遇到dynamic_cast的奇怪行为时,我正在实现T*Array::operator[]以包括必要的类型检查,以确保它返回有效对象(或null)。这正是我试图做的。浅拷贝数组(可选)动态检查转换和元素访问。转换很容易,我们只需定义一个模板副本构造函数,除了使用动态\u强制转换检查的原始构造函数之外(在这里可以保证这两种类型不相同),问题在于元素访问。我可以想到两种方法:一种方法涉及运算符[]的代理类返回值,而不是T*&,它根据数组的实际类型检查所有读写操作,我认为这是不可能的。第二种方法涉及运算符[]内部的检查它本身,我遇到了麻烦,不能阻止非法写入,但如果有人试图访问非法元素,它会识别错误的状态。我的最终方法基本上与您的方法相同。我不确定它的正确性,但坦率地说,除了重新解释cast之外,我想不出任何可以绕过它的情况这可以防止将一个
新整数
赋值到一个
数组
中,该数组恰好在该索引处有一个
字符串*
?如编写的测试,
动态转换(静态转换(内部[index])
,只会验证传入的整数是否可以强制转换为
对象*
,而不是
字符串*
…否?它不会阻止将无效对象插入数组。但是它会阻止在模板上下文中使用这些对象,从而使它们无效。是的,您的假设完全正确,而不是复制机制。我有一个代理的想法,但由于
o[0] = new Integer(1); //  technically illegal but no idea how to check
Array<String*> w = o;     //  this fails with an exception
String* str = v[0];     //  should fail horribly as well
cout << str << endl;