在 C 或 C++ 中处理循环依赖的最佳方法?

Best way to deal with cyclic dependancies in C or C++?

在 C 中,当我需要这个时:

文件a.h:

#ifndef A_H
#define A_H

#include "b.h"

typedef struct A { B* second_struct; } A;

#endif /* !A_H */

文件b.h:

#ifndef B_H
#define B_H

#include "a.h"

typedef struct B { A* first_struct; } B;

#endif /* !B_H */

我冒昧地以这种方式重新排列:

typedef struct A A;

#ifndef A_H
...

b.h也是如此)

我在 header 的第一行中用 class A; 在 C++ 中做了完全相同的事情。


然而,有人告诉我这是一个不好的做法,在 C 中,因为 typedef 应该创建另一个类型并且可能与之前相同的 typedef 冲突,以防多重包含。

他还告诉我,出于这些原因,在 header 守卫之外不应有任何声明。

所以,他建议我在 struct B(和 vice-versa)的声明之前在 b.h 中放置一个 typedef struct A A;,因为这是我需要它的地方.

我的问题是:

在这种情况下,typedef .. A;b.h中丢失不是很危险吗?

更一般地说,处理这种依赖关系的最佳做法是什么?

处理这类依赖关系的最佳做法通常是避免它们。不过,这并不总是可能的。

我会这样做:

a.h

#ifndef A_H
#define A_H

#include "b.h"

// Forward decls
struct B;    

typedef struct A { struct B* second_struct; } A;

#endif /* !A_H */

b.h

#ifndef B_H
#define B_H

#include "a.h"

// Forward decls
struct A;

typedef struct B { struct A* first_struct; } B;

#endif /* !B_H */

在 C 和 C++ 中均有效。

前向声明应尽可能简单,因此应避免其中的 typedef,这在本例中很简单。这仅意味着您必须在 B.

的定义中使用 struct A* 而不是 A*

关于 include 守卫之外的 typedef:这绝对不是标准做法。

#include "a.h" 确保 struct A 的前向声明存在,乍一听这听起来很诱人。问题是 struct A 可能是不完整的类型不再明显。

前向声明也是对未来的警告reader它们可能正在处理不完整的类型。