C++ 班长

C++ 班长,c++,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将增加

我知道下面的内容很糟糕,但我的印象是班级的第一个成员是班级的起始地址。错了吗

   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。它总是正确的还是未定义的?当用户定义了构造函数或虚拟函数时,为什么它会改变?

是的,你完全错了,你不能接受任何类似的东西,当然,这些是C++所不能保证的编译器特定的契约。


我相信您把类与C++数组混淆了:例如,指向char数组第一个成员的指针与指向该数组的指针相同。<是的,你绝对错了,你绝对不能接受任何类似的东西,这些是C++所不能保证的编译器特定的契约。


我相信您把类与C++数组混淆了:例如,指向char数组第一个成员的指针与指向该数组的指针相同。 只有当您的类是标准布局类型时,这才成立。这可以使用类型trait进行测试

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

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

对象指针可以显式转换为不同类型的对象指针。当“指向T1的指针”类型的PRV值转换为“指向cv T2的指针”类型时, 如果T1和T2均为标准布局类型3.9,且T2的对齐要求不比T1严格,则结果为静态_caststatic_castv, 或者如果其中一种类型为void。将类型为“指向T1的指针”的PR值转换为类型为“指向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;
}

只有当您的类是标准_布局类型时,这才成立。这可以使用类型trait进行测试

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

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

对象指针可以显式转换为不同类型的对象指针。当“指向T1的指针”类型的PRV值转换为“指向cv T2的指针”类型时, 如果T1和T2均为标准布局类型3.9,且T2的对齐要求不比T1严格,则结果为静态_caststatic_castv, 或者如果其中一种类型为void。将类型为“指向T1的指针”的PR值转换为类型为“指向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;
}

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

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

是否有任何与规范相关的支持链接?我不太明白为什么这个答案是否定的,因为它不正确。事实上,标准布局确实保证了这一点,即使是原始的C规范也做到了。如果第一个成员是层次结构中的虚拟函数,该怎么办?如果类本身是层次结构的一部分呢?我认为要么你不确定你在谈论什么,要么你没有考虑所有的可能性…@jaffar exaclty这就是标准布局所保证的。如果你的类有任何这些“障碍”,它不是标准布局。另一方面,如果你的类是标准布局,那么它定义得很好。有没有规范的支持链接?我不太明白为什么这个答案是否定的,因为它是不正确的。事实上,标准布局确实保证了这一点,即使是原始的C规范也做到了。如果第一个成员是层次结构中的虚拟函数,该怎么办?如果类本身是层次结构的一部分呢?我认为要么你不确定你在说什么,要么你没有考虑到
g所有的可能性…@jaffar exacly这是标准布局所保证的。如果你的类有任何这些“障碍”,它不是标准布局。另一方面,如果您的类是标准布局,那么它是定义良好的。是的。真糟糕!太糟糕了,答案应该是无关紧要的。你的问题无关紧要!你所能做的就是糟糕的设计和大部分未定义的行为。简单的回答:永远不要那样做!它可能在今天工作,但没有定义它明天或与任何其他编译器一起工作。是的。真糟糕!太糟糕了,答案应该是无关紧要的。你的问题无关紧要!你所能做的就是糟糕的设计和大部分未定义的行为。简单的回答:永远不要那样做!它可能在今天可以工作,但没有定义它明天是否可以工作,也没有定义它是否可以与任何其他编译器一起工作。您可以将指向标准布局类型对象的指针转换为指向其第一个成员的指针,但我不完全确定这一点。你能从标准中添加一个支持性的引用吗?大多数规则都很直观,但规则3和6对我来说似乎很可笑,我甚至不明白5在说什么。@ValekHalfHeart 3允许编译器根据访问权限对类成员重新排序。6需要与5一起阅读;如果类具有非静态数据成员,则其所有基类每5个都必须为空,但是,如果第一个非静态数据成员的类型与基类相同,则编译器必须为它和空基类子对象提供不同的地址,因为它们是不同的对象。@BoBTFish I添加了标准中描述这一点的部分。我不能说我的解释是否正确,但看起来,从A到B的转换应该可以,而从B到A的转换是未指定的。您可以将指向标准布局类型对象的指针转换为指向其第一个成员的指针,但我不能完全确定这一点。你能从标准中添加一个支持性的引用吗?大多数规则都很直观,但规则3和6对我来说似乎很可笑,我甚至不明白5在说什么。@ValekHalfHeart 3允许编译器根据访问权限对类成员重新排序。6需要与5一起阅读;如果类具有非静态数据成员,则其所有基类每5个都必须为空,但是,如果第一个非静态数据成员的类型与基类相同,则编译器必须为它和空基类子对象提供不同的地址,因为它们是不同的对象。@BoBTFish I添加了标准中描述这一点的部分。我不能说我是否正确地解释了它,但看起来,从A到B的转换应该是好的,而从B到A的转换是不确定的。