これは、X/Motif の古代の記憶に基づいた、昔ながらの C ポリモーフィズムの図です。
識別された共用体 (または null の可能性がある子ポインターを持つ型付き構造体) だけが必要な場合は、おそらくあなたの場合はより簡単です。
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);