我在C中创建了一个简单的列表结构,它使用void *指针保存任何类型的数据,如:
struct node
{
void *the_data;
node *next;
};
它工作正常,但我有一些列表,例如,只包含列表中的struct_a和另一个列表中的struct_b。我需要在单个if()问题中检查列表的第一个元素是struct_a类型还是struct_b类型,因此我知道此列表所持有的数据。这该怎么做?感谢
修改
我已经提出了一个足以解决问题的简单解决方案,如果它是最好的,那就不知道了。
struct node
{
void *data;
node *next;
}
我添加了一个"描述符" node,包含第一个节点的地址和有关类型的信息:
struct list_desc
{
node *list;
short int type;
}
我会将它与一些像
这样的宏一起使用#define __data_type1 10
#define __data_type2 20
所以稍后我可以比较if(struct.type == __data_tipe1)等......
答案 0 :(得分:4)
C不提供运行时类型信息。您必须自己添加此信息。有两种基本方法(假设C99或C11):
您可以使用具有匿名联合的结构(可能):
struct Node {
enum {
OBJ_TYPE_A,
OBJ_TYPE_B
} type;
union {
struct NodeA a;
struct NodeB b;
}; // anonymous, if a name is added, you have an additional field name
};
...
struct Node *node = ...;
if ( node->type == OBJ_TYPE_A ) {
node->a.a_field = whatever;
...
缺点是你必须在一个地方定义联合,而不能在另一个模块中扩展它。
更好的方法是使用匿名结构构建一个真正的类层次结构:
struct Node {
enum {
OBJ_TYPE_A,
OBJ_TYPE_B
} type;
struct Node *next;
};
struct NodeA {
struct Node; // base class, first field!
int a_field;
};
struct NodeB {
struct Node; // base class, first field!
float b_field;
};
void take_node(struct Node *node)
// takes a generic pointer to the base-class
{
if ( node->type == OBJ_TYPE_A ) {
struct NodeA *a_node = (NodeA)node;
a_node->a_field = whatever;
} else if ...
...
}
// until here that is normal C99
int main(void)
{
struct NodeA anode = { .type = OBJ_TYPE_A, .a_field = 42 };
struct NodeB bnode = { .type = OBJ_TYPE_B, .b_field = 4.2 };
take_node((Node *)&anode); // standard: inhibits type checking
take_node(&anode); // plan9-extension: no cast required
take_node(&bnode); // plan9-extension: no cast required
}
Pro在创建新的子结构时不需要扩展基本结构(它不依赖于子结构)。匿名结构允许创建直接子项的子项和访问字段,如OOP中所期望的那样(没有字段说明符链:child1_1_1_ptr->child1_1.child1.base.base_field
,而只是child1_1_1_ptr->base_field
)。
take_node
的后两次调用使用gcc C-extension -fplan9-extensions
。这样可以避免在仍然启用类型检查(基类或子类)的同时强制转换为基类。这是向OOP迈出的一大步。
这可以扩展到全尺寸OOP方法,包括虚拟方法。但是,使用像C ++这样真正的OOPL变得更容易了。
答案 1 :(得分:3)
C不包含有关指针指向的运行时信息。您可以创建一个包含类型字段和联合的结构,其中包含您要存储的任何内容。
enum node_type {
NODE_TYPE_STRING,
NODE_TYPE_INT,
NODE_TYPE_DOUBLE,
NODE_TYPE_OTHER_STRUCT
};
struct other_struct {
// define some fields
};
struct node_data {
enum node_type type;
union {
char *string;
int i;
double d;
struct other_struct other;
} data;
};
答案 2 :(得分:2)
C是一种编译语言。有关"类型"的信息结构或任何其他变量只存在于编译时,而不是运行时。如果你需要多态性,你必须自己实现它。
一种常见的方法是使一组结构的第一个元素成为一个标识符。一个数字(可能是信息类型表的索引),或类似信息结构的地址。然后你可以为这些结构中的任何一个分配指针,并检查第一个字段以决定如何处理它。
答案 3 :(得分:1)
您如何看待这个:
typedef enum tag_ElementType
{
ElementA,
ElementB
} en_ElementType;
typedef struct tag_Container
{
en_ElementType ElementType;
void *pData;
} st_Container;
在这种情况下,您的结构将如下所示:
typedef struct tag_node
{
st_Container the_data;
struct tag_node *next;
} st_node;