注意:这不是 C++ 问题,我不能使用 C++ 编译器,只能使用 C99。
这是有效的(可接受的、漂亮的)代码吗?
typedef struct sA{
int a;
} A;
typedef struct aB{
struct sA a;
int b;
} B;
A aaa;
B bbb;
void init(){
bbb.b=10;
bbb.a.a=20;
set((A*)&bbb);
}
void set(A* a){
aaa=*a;
}
void useLikeB(){
printf("B.b = %d", ((B*)&aaa)->b);
}
简而言之,当我需要它的特定行为时,将“子类”转换为“父类(super class)”并在将“父类(super class)”转换为“子类”之后是否有效?
谢谢
最佳答案
首先,C99 标准允许您将任何结构指针转换为指向其第一个成员的指针,反之亦然(6.7.2.1 结构和 union 说明符):
13 Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.
换句话说,在您的代码中您可以自由地:
- 将
B*
转换为A*
— 它将始终正常工作, - 将
A*
转换为B*
— 但如果它实际上并不指向B
,您将遇到随机失败访问更多成员, - 将通过
A*
指向的结构分配给A
— 但如果指针是从B*
转换而来的,则只有公共(public)成员将被分配和B
的其余成员将被忽略, - 将
B*
指向的结构赋值给A
——但必须先转换指针,注意(3)。
因此,您的示例几乎是正确的。但是 useLikeB()
将无法正常工作,因为 aaa
是类型为 A
的结构,您按照第 (4) 点中的说明分配了它。这有两个结果:
- 不常见的
B
成员实际上不会被复制到aaa
(如(3)中所述), - 您的程序将随机尝试访问
A
而不是B
而失败(您正在访问一个不存在的成员,如 (2 )).
为了更实际地解释这一点,当您声明 A
时,编译器会保留容纳 A
的所有成员所需的内存量。 B
有更多的成员,因此需要更多的内存。由于 A
是常规变量,它不能在运行时更改其大小,因此不能保存 B
的剩余成员。
请注意,通过 (1) 您实际上可以使用指向成员的指针而不是转换更好的指针,并且它将允许您访问任何成员,而不仅仅是第一个成员。但请注意,在这种情况下,相反的方法将不再起作用!
关于C、结构指针多态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12018936/