班级的第一个成员

时间:2014-08-19 07:30:57

标签: c++

我知道以下情况很糟糕,但我的印象是,班级的第一个成员是班级的起始地址。这是错的吗?

   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.它总是真的还是未定义的?当我们有用户定义的构造函数或虚函数时,为什么会改变?

3 个答案:

答案 0 :(得分:4)

仅当您的类属于standard_layout类型时才会出现这种情况。您可以使用类型特征is_standard_layout

进行测试
 std::cout << std::is_standard_layout<A>::value << '\n';
 std::cout << std::is_standard_layout<B>::value << '\n';

对于其他类,您可以在内存中存储其他信息,这些信息是特定于编译器的,而不是标准化的。您可以查看This question,其中讨论并显示了一些内存布局。

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

  

可以将对象指针显式转换为不同类型的对象指针。当“指向T1的指针”类型的prvalue v转换为“指向cv T2的指针”类型时,   结果是static_cast(static_cast(v))如果T1和T2都是标准布局类型(3.9)并且T2的对齐要求不比T1更严格,   或者如果任何一种类型无效。将“指向T1的指针”的prvalue转换为“指向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;
}

答案 1 :(得分:2)

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

答案 2 :(得分:-1)

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

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