1

我知道以下内容不好,但我的印象是类的第一个成员是类的起始地址。这是错的吗 ?

   class A{
      public:
       int a;
       int b;
   };
  
   class B{
     public :
       int x;
   };

   int main()
   {
        B *pb=new B();
        A *pa=(A*)pb;
        pa->a++;
   }

我的印象是pb->x会增加 1。它总是 true 还是 undefined ?为什么当我们有用户定义的构造函数或虚函数时它会改变?

4

3 回答 3

4

仅当您的类是类型时才适用standard_layout。您可以使用类型特征进行测试is_standard_layout

 std::cout << std::is_standard_layout<A>::value << '\n';
 std::cout << std::is_standard_layout<B>::value << '\n';

对于其他类,您在内存中存储了额外的信息,这些信息是特定于编译器的而不是标准化的。你可以看看这个问题,其中讨论和展示了一些内存布局。

对于您的第二个示例/问题,该标准具有以下引用(5.2.10/7,N3337 草案):

对象指针可以显式转换为不同类型的对象指针。当“指向 T1 的指针”类型的纯右值 v 转换为“指向 cv T2 的指针”类型时,如果 T1 和 T2 都是标准的,则结果为 static_cast<cv T2*>(static_cast<cv void*>(v)) -layout 类型 (3.9) 和 T2 的对齐要求不比 T1 更严格,或者如果任一类型为 void。将“指向 T1 的指针”类型的纯右值转换为“指向 T2 的指针”类型(其中 T1 和 T2 是对象类型,并且 T2 的对齐要求不比 T1 的对齐要求更严格)并返回其原始类型会产生原始类型指针值。未指定任何其他此类指针转换的结果。

如果我正确阅读并解释了这一点,那么您的示例未指定,因为 A 的对齐要求大于 B 的对齐要求。但是,另一种方式应该没问题,例如:

int main()
{
    A *pa=new A();
    B *pb=reinterpret_cast<B*>(pa);
    pb->x++;
    std::cout << pa->a;
}
于 2014-08-19T07:36:48.143 回答
2

通过将指针强制转换为另一个类,您违反了严格的别名。如果您的类是标准布局,则只能将其转换为第一个成员的类型。

于 2014-08-19T07:38:26.690 回答
-1

是的,您绝对错了,您永远不能认为这样的事情是理所当然的,这些是 C++ 不保证的编译器特定合同。

我相信您将类与 C++ 数组混淆了:例如,指向 char 数组的第一个成员的指针与指向该数组的指针相同。

于 2014-08-19T07:35:28.733 回答