这是基于 X/Motif 的古老记忆的老式 C 多态性的图示。
如果您只想要一个可区分的联合(或者甚至只是一个带有可能为空的子指针的类型化结构),那么在您的情况下它可能更简单。
enum NodeType { TFile, TFolder };
struct Node {
enum NodeType type;
const char *name;
struct Node *next;
};
struct FileNode {
struct Node base_;
};
struct FolderNode {
struct Node base_;
struct Node *children;
/* assuming children are linked with their next pointers ... */
};
这是构造函数 - 我将填充链接列表作为读者的练习......
struct Node* create_file(const char *name) {
struct FileNode *file = malloc(sizeof(*file));
file->base_.type = TFile;
file->base_.name = name; /* strdup? */
file->base_.next = NULL;
return &file->base_;
}
struct Node* create_folder(const char *name) {
struct FolderNode *folder = malloc(sizeof(*folder));
folder->base_.type = TFolder;
folder->base_.name = name;
folder->base_.next = NULL;
folder->children = NULL;
return &folder->base_;
}
现在我们可以遍历层次结构,检查每个节点的类型并做出适当的响应。这依赖于第一个成员子对象与父对象的偏移量为零 - 如果不成立(或者您需要多重继承),则必须使用offsetof
在基本类型和“派生”类型之间进行转换。
void walk(struct Node *root,
void (*on_file)(struct FileNode *),
void (*on_folder)(struct FolderNode *))
{
struct Node *cur = root;
struct FileNode *file;
struct FolderNode *folder;
for (; cur != NULL; cur = cur->next) {
switch (cur->type) {
case TFile:
file = (struct FileNode *)cur;
on_file(file);
break;
case TFolder:
folder = (struct FolderNode *)cur;
on_folder(folder);
walk(folder->children, on_file, on_folder);
break;
}
}
}
请注意,我们有一种多态的基本类型,但我们可以使用虚函数进行更完整的多态设置,而不是打开类型枚举。只需添加一个指向 的函数指针Node
,例如:
void (*visit)(struct Node *self,
void (*on_file)(struct FileNode *),
void (*on_folder)(struct FolderNode *));
并拥有create_file
并将create_folder
其设置为适当的功能(例如,visit_file
或visit_folder
)。然后,而不是打开枚举类型,walk
只需调用
cur->visit(cur, on_file, on_folder);