C、结构指针多态

标签 c inheritance polymorphism

注意:这不是 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.

换句话说,在您的代码中您可以自由地:

  1. B* 转换为 A* — 它将始终正常工作,
  2. A* 转换为 B* — 但如果它实际上并不指向 B,您将遇到随机失败访问更多成员,
  3. 将通过A* 指向的结构分配给A — 但如果指针是从B* 转换而来的,则只有公共(public)成员将被分配和 B 的其余成员将被忽略,
  4. B*指向的结构赋值给A——但必须先转换指针,注意(3)。

因此,您的示例几乎是正确的。但是 useLikeB() 将无法正常工作,因为 aaa 是类型为 A 的结构,您按照第 (4) 点中的说明分配了它。这有两个结果:

  1. 不常见的B成员实际上不会被复制到aaa(如(3)中所述),
  2. 您的程序将随机尝试访问 A 而不是 B 而失败(您正在访问一个不存在的成员,如 (2 )).

为了更实际地解释这一点,当您声明 A 时,编译器会保留容纳 A 的所有成员所需的内存量。 B 有更多的成员,因此需要更多的内存。由于 A 是常规变量,它不能在运行时更改其大小,因此不能保存 B 的剩余成员。


请注意,通过 (1) 您实际上可以使用指向成员的指针而不是转换更好的指针,并且它将允许您访问任何成员,而不仅仅是第一个成员。但请注意,在这种情况下,相反的方法将不再起作用!

关于C、结构指针多态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12018936/

相关文章:

c++ - 使用 volatile long 作为原子

c - 如何声明和初始化指向char指针数组的指针数组?

c - 64 位比较和交换 (CAS) 应该在 32 位机器上工作吗? (或 64 位机器?)

javascript - 通过另一个函数透明地传递一个函数的参数

c++ - 从未定义它的基类调用纯虚函数?

c# - 通过强制转换或鸭式输入不同的对象类型来重用相同的功能

ios - 面向对象编程的正确概念

c - 读取文件 - fgets 读取\n 不是的地方

java - 一个对象可以包含它的父类(super class)吗?

c++ - 这个函数调用真的有歧义吗?