【问题标题】:C++ type casting int * to class [duplicate]C ++类型转换int *到类[重复]
【发布时间】:2012-05-10 18:49:01
【问题描述】:

可能重复:
Regular cast vs. static_cast vs. dynamic_cast
Undefined, unspecified and implementation-defined behavior

我遇到了一个奇怪的问题。在下面的 sn-p 中我定义了一个类

   class NewClass
   {
      public:
         void Test()
         {
             cout<<"NewClass Test"<<endl;
         }
   };

在我的 main() 方法中,我写:

        void main()
        {
           int *ptr = new int();
           NewClass *n = ((NewClass *)ptr);
           n->Test();
        }

它会显示“NewClass Test”。我不明白如何将 any 指针类型转换为 NewClass 并且仍然可以正常工作。

提前致谢!

【问题讨论】:

  • 未定义的行为意味着任何事情都可能发生,包括欺骗您认为它有效。

标签: c++ casting


【解决方案1】:

这是工作中的静态调度。在这种情况下,this 确实是不必要的(例如,在 NewClass::Test() 中没有使用或依赖它)。

转换为NewClass *n = ((NewClass *)ptr); 是按地址进行类型转换,在这种情况下没有类型检查。换句话说,您没有在任何地方创建新的NewClass 实例,您只是将int* 指定的地址处的内存视为NewClass*。这是一个危险的转换,应该避免。如果您需要通过丢失类型安全性的地址(例如void*)来汇集对象,请始终确保两端都知道发送和接收的内容。幸运的是,擦除类型安全性正变得越来越少。

结果是不确定的,但在大多数情况下,您应该预料到会产生不良的副作用,并且您应该不惜一切代价避免重新解释数据。

在这种情况下,编译器可能会插入结果,因为它知道它们。此外,没有出现错误,因为在这种情况下没有实际依赖对象的地址或状态:Test() 不依赖this 的状态/数据/成员/动态方法/vtable。

如果您要将诸如 std::strings 之类的成员添加到 NewClass 并打印它们...您可以预期事情会比现在更早爆发:)

如果危险不明显:这是一个极其危险的转换——int* 支持的所有数据都被重新解释为NewClass*,以及它的所有内部存储器和结构(例如 vtables 和魔法cookie) 被相应地重新解释。您的程序段错误很快就会出现,无论是通过读取超出分配结束(int*),还是将int 视为完全不相关的类型 - 在这种情况下,请考虑内存布局具有 vtable 或数据的类,例如将一些 std::strings 添加到 NewClass,并读取和写入这些成员。

【讨论】:

  • 谢谢。我想知道 NewClass 对象在我的代码中实例化的位置。我理解关于没有类型检查的一点,也理解将任何东西转换为任何东西都是一种糟糕的编程习惯。投入赞赏。干杯!
  • @GeeKay 这就是我所说的“按地址进行类型转换”。没有NewClass - 您只是将int* 视为NewClass* :) 在这种情况下,您将看到NewClass 既未创建也未销毁。 (添加回答...)
【解决方案2】:

在您开始考虑一个复杂的为什么它不应该起作用之前,请先考虑一个简单的场景来帮助您尝试和想象它。

类是一种数据结构,其附带方法。当然编译器是不同的,所以行为可能被认为是未定义的,但暂时忽略这一点。

你有一个空的数据结构(即没有数据),但还有一个附加的方法——Test()。

所以当你声明一个指向某个东西的指针(你关心的 int)时,指针只是指向一些内存。现在你有了一个新的 Int(),因此 ptr 指向的内存是整数大小的。

由于您的类没有数据并且它没有内部结构需要内存中的对象以特定方式(例如虚拟方法)在内存中布局,您可以认为您指向任何东西或事实上什么都没有,因此可以调用你的方法。

像这样创建一个类,看看会发生什么:

   class NewClass 
   { 
      private int i;
      public: 
         void Test() 
         { 
             cout<<"NewClass Test i="<< i << endl; 
         } 
   };

    void main() 
    { 
       int *ptr = new int();
       *ptr =  10; 
       NewClass *n = ((NewClass *)ptr); 
       n->Test(); 
    } 

看看打印出来的内容。

如果您理解这一点,请尝试阅读您的编译器,了解它是如何布置对象的。这将告诉您很多关于为什么在您的平台上存在这种行为。

【讨论】:

    【解决方案3】:

    这似乎是未定义的行为。但是,您始终可以在 c++ 中使用 reinterpret-cast 执行此操作 滥用 reinterpret_cast 运算符很容易不安全。除非所需的转换本质上是低级的,否则您应该使用其他强制转换运算符之一。 reinterpret_cast 运算符可用于 char* 到 int* 或 One_class* 到 Unrelated_class* 等转换,这些转换本质上是不安全的。

    【讨论】:

      【解决方案4】:

      您的方法未声明为虚拟方法。这意味着对它的调用完全由编译器解析,就像它是一个非方法函数一样,只是你必须在一个正式为 NewClass 的变量上调用它。

      您的编译器可能使用virtual method tables 来调度对虚拟方法的调用,如果该方法是虚拟的,您最终可能会用垃圾代替 VMT,然后您就会开始崩溃。

      也就是说,行为是未定义的,这意味着在任何一种情况下都可能发生任何事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-07
        • 2021-07-29
        • 1970-01-01
        • 2011-03-17
        • 1970-01-01
        • 2012-06-19
        相关资源
        最近更新 更多