gpt4 book ai didi

c++ - 不兼容的指针分配是否需要在 C 中实现多态性

转载 作者:搜寻专家 更新时间:2023-10-31 02:08:26 26 4
gpt4 key购买 nike

我尝试用以下代码在 C 中模拟 C++ 的多态性:

#include<stdio.h>

typedef struct Base {
void (*out) (void);
} Base;

typedef struct Derived {
Base base;
int x;
} Derived;

void base_out() {
printf("base\n");
}

void derived_out() {
printf("derived\n");
}

void foo(void) {
Derived d;
Base b;
b.out = base_out;
d.base.out = derived_out;

Base *p;
p = &b;
p->out();
//warning: assignment from incompatible pointer type
p = &d;
p->out();
}

int main(void) {
foo();
}

但是当p = &d 时我必须做不兼容的指针赋值。为了让它工作,Derived 中的 base 成员也需要成为第一个成员。如何避免这两种情况?

最佳答案

不兼容的指针赋值是不必要的。根据 C 2011 [draft N1570] 6.7.2.1 15,“指向结构对象的指针,经过适当转换,指向其初始成员(或者如果该成员是位域,则指向它所在的单元),并且反之亦然。”因此,当 Derived 的第一个元素时是 Base对象,指向 Derived 的指针可以转换为指向 Base 的指针.和一个指向 Base 的指针那是 Derived 中的第一个成员可以转换为指向 Derived 的指针.

所以这是合法的。出于安全考虑,编译器可能会警告您,因为它不常见。使用显式转换可以避免这种情况:

p = (Base *) &d;

或者,您可以直接获取基地址:

p = &d.base;

但是,从 Base 返回到 Derived 仍然需要转换:

Derived *x = (Derived *) p;

至于将基地放在第一个成员之外的其他地方,那么你的立场就更不稳定了。派生到基础的方向仍然很容易; p = &d.base很好。换句话说,这可能与合法 C 最接近:

  1. 获取指向基数的字符类型指针:char *c = (char *) p .在 C 语言中,将任何指向对象的指针转换为指向字符类型的指针是合法的,这会为您提供指向对象第一个字节的指针。

  2. Derived 的开头减去字节数到 Base成员:c -= offsetof(Derived, base) . (这需要包括 <stddef.h> 。)由于 c指向 Base 的第一个字节在Derived , 它指向 Derived 中的一个字节,而且你大部分(见下文)被允许治疗Derived作为一个字节数组,所以我们可以减去回到开头。 offsetof宏为此提供了字节数。

  3. 将字符指针转换为指向 Derived 的指针: Derived *x = (Derived *) c .在这里,我们站稳了脚跟。如果我们将指针转换为 Derived到一个字符指针,我们可以立即将它转换回来。但是我们并没有通过那种方式得到这个指针。它指向同一个字节,但我不清楚 C 标准是否支持这个。 (实际上,上面的第 2 步有一个类似的问题;一个对象可以解释为一个字符数组,但我们是从一个方向来的,我不确定 C 标准实际上是否支持它。)

将这些放在一起,转换将是:

Derived *x = (Derived *) ((char *) p - offsetof(Derived, base));

考虑到支持的不确定性,我只会在实验代码或类练习中使用它,除非我从我使用的 C 实现中得到支持该指针算法的保证。最好坚持将基数作为第一个元素,因为这些转换严格符合 C。

关于c++ - 不兼容的指针分配是否需要在 C 中实现多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47543996/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com