c - C 中 "emulate"多态性时使用结构成员和转换结构指针之间的区别

标签 c pointers

我不确定我的措辞在技术上是否正确,因此请纠正我的问题标题和正文。

所以基本上我的问题是关于在 C 中模拟多态性。例如,假设我有一棵树,并且有一个 struct tree_node 类型。我有一些函数可以帮助我插入节点、删除节点等,例如:

void tree_insert(tree_node **root, tree_node *new_node);

然后我开始为我的应用程序构建其他东西,并且需要使用这棵树来维护,比如说,家庭成员。但是对于人类,我有另一个结构体,我们称之为“struct human_node”,其定义如下,例如:

typedef struct human_node_ {
    tree_node t_node;
    char *name;
} human_node;

现在显然我想使用我为通用树构建的那些树实用函数。但它们采用 tree_node 指针。现在进行多态性模拟。所以这里有两个选择,一种是强制转换我的 human_node,一种是使用 human_node 中的 t_node 成员:

human_node *myfamily_tree_root, *new_family_guy;
//some initialization code and other code later...
tree_insert((tree_node **)&myfamily_tree_root, &(new_family_guy->t_node));

为了简洁起见,我将这两种方法都放在上面的一个函数调用中。

这正是我困惑的地方。那么我应该使用哪一个,更重要的是,为什么?

最佳答案

两者都是标准的,但一般来说,如果您可以避免类型转换,那么您应该选择避免类型转换的解决方案。

这种内联数据结构实现的一个常见问题是甚至不要求树节点(或等效元素)是结构中的第一个元素,因为您可能希望将节点输入到多个树中。那么你肯定想使用第二种方法。要在 tree_node 元素和包含的结构之间进行转换,您必须有一些黑魔法宏,但这是值得的。例如,在 avl 树的实现中,我有这些宏:

#ifndef offsetof
#define offsetof(s, e) ((size_t)&((s *)0)->e)
#endif

/* the bit at the end is to prevent mistakes where n is not an avl_node */
#define avl_data(n, type, field) ((type *)(void*)((char *)n - offsetof(type, field) - (n - (struct avl_node *)n)))

所以我可以有这样的东西:

struct foo {
    int data;
    struct avl_node tree_node_1;
    struct avl_node tree_node_2;
};

int
tree_node_1_to_data(struct avl_node *x)
{
     return avl_data(x, struct foo, tree_node_1)->data;
}

如果您选择使代码变得通用,您肯定希望引用对 tree_node 成员的引用,而不是将指针强制转换为结构体。

关于c - C 中 "emulate"多态性时使用结构成员和转换结构指针之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21874744/

相关文章:

c - 有没有一种方法可以将指针传递给变量,而无需根据函数原型(prototype)事先定义它,如果其参数需要指针作为一个变量?

c++ - 为什么C++不能同时释放内存和指针

c - 试图了解释放分配的内存时的行为

c++ - 编译要在 C++ 版本中链接的 C 库...是否需要指定 C++ 标准?

我们可以在结构中使用宏吗?

c - 代码中的运行时错误

c - 在外部结构初始化中将内部结构初始化为常量

c - 使用 SWIG 将指向结构的指针从 TCL 传递到 C 函数

我可以通过同时索引 c 中的两个矩阵来将矩阵的值传递给另一个矩阵吗?

c - 删除二维整数数组,在 C 中将指针设置为空