blo*_*low 0 c polymorphism inheritance
注意:这不是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);
}
Run Code Online (Sandbox Code Playgroud)
简而言之,当我需要指定的行为时,将"子类"转换为"超类"并重铸后的"超类"到"子类"是有效的吗?
谢谢
首先,C99标准允许您将任何结构指针强制转换为指向其第一个成员的指针,另一种方式(6.7.2.1结构和联合说明符):
13在结构对象中,非位字段成员和位字段所在的单元具有按声明顺序增加的地址.指向适当转换的结构对象的指针指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.结构对象中可能存在未命名的填充,但不是在其开头.
换句话说,在您的代码中,您可以自由地:
B*为A*- 它将始终正常工作,A*为B*- 但是如果它实际上没有指向B,那么您将获得访问其他成员的随机失败,A*对A-但如果指针是从转换B*,只有公共元件将被分配和的其余成员B都将被忽略,B*对A-但你必须指针先转换方法及注意事项(3).所以,你的例子几乎是正确的.但是useLikeB()不能正常工作,因为你指定aaa的类型的结构A如第(4)节所述.这有两个结果:
B成员实际上不会被复制aaa(如(3)所述),A一样B,它不是(你所访问的成员是不存在的,如(2)).要以更实际的方式解释这一点,当您声明A编译器保留保存所有成员所需的内存量时A.B有更多的成员,因此需要更多的记忆.作为A常规变量,它不能在运行时更改其大小,因此无法保留其余成员B.
作为一个注释,通过(1)你几乎可以指向成员而不是转换更好的指针,它将允许你访问任何成员,而不仅仅是第一个成员.但请注意,在这种情况下,相反的情况将不再适用!