2011-01-27 106 views
47

对于如何避免头文件的循环依赖关系有什么建议吗?避免头文件的循环依赖关系

当然,从一开始,我尽量设计项目尽可能透明。但是,随着越来越多的功能和类被添加,并且项目变得越来越不透明,循环依赖开始发生。

是否有任何通用,验证和工作规则?谢谢。

回答

48

看你是否有循环依赖,那么你做错了什么。

至于例如:

foo.h 
----- 
class foo { 
public: 
    bar b; 
}; 

bar.h 
----- 
class bar { 
public: 
    foo f; 
}; 

是违法的,你可能想:

foo.h 
----- 
class bar; // forward declaration 
class foo { 
    ... 
    bar *b; 
    ... 
}; 

bar.h 
----- 
class foo; // forward declaration 
class bar { 
    ... 
    foo *f; 
    ... 
}; 

这是确定的。

一般规则:

  1. 确保每头可以被包含在它自己的。
  2. 如果您可以使用正向声明,请使用它们!
+0

+1你好Artyom,谢谢你的回复。更频繁地使用前向声明可能会有所帮助。 – 2011-01-27 13:49:11

+0

@Artyom:如果指针是为了拥有资源,我建议使用`scoped_ptr`或`unique_ptr`。如果指针仅仅是一个对象的引用,那么可能有必要使用Observer模式,以便每当引用的对象被销毁时它就“未设置”。 – 2011-01-27 14:16:01

4

根据您的预处理器功能:

#pragma once 

#ifndef MY_HEADER_H 
#define MY_HEADER_H 
your header file 
#endif 

如果你觉得很无聊,设计的头文件从Hwaci(SQLite和化石DVCS的设计师)也许makeheaders可能是对你的兴趣。

+2

这与其说是为了避免循环依赖,以避免错误“符号重新定义”。尽管如此,这是一个标准的,绝对需要的练习。 – 2011-01-27 13:19:35

+0

你好Benoid,是的,我不得不同意Peter Torok。这在每本教科书和必须使用的游戏中都有所解释。非常感谢您的回复。 – 2011-01-27 13:59:27

6

一般的方法是将共同性分解成第三个头文件,然后由两个原始头文件引用它们。

Circular Dependency Best Practice

+0

+1嗨,Ed,这是另一个非常好的建议。谢谢。 – 2011-01-27 13:49:55

+0

我检查了你提供的链接,它显示了重新设计分类以避免循环依赖的好例子。 – 2011-01-27 14:18:14

+0

谢谢,我也喜欢它;-) – 2011-01-27 14:34:00

3

你想要的是一个layered approach。您可以定义哪些模块可以依赖于较低层模块,但是应该使用observers。现在您仍然可以定义图层的细粒度以及是否接受图层中的循环依赖关系,但在这种情况下,我会使用this

15
  • 在可能的情况下使用前向声明。
  • 如果只有cpp文件需要,则将任何头文件移出头文件并移入相应的cpp文件。执行此操作最简单的方法是使#include "myclass.h"首先包含在myclass.cpp中。
  • 在不同类之间的交互点引入接口可以帮助减少依赖关系。
3

在一般的头文件应该正向声明,而不是包括其他头,只要有可能。

还要确保您坚持每个标题一个类。

那你几乎肯定不会出错。

最糟糕的耦合通常来自臃肿的模板代码。由于必须在头文件中包含定义,因此通常会导致必须包含各种头文件,然后使用该模板的类将包含模板头文件,其中包含大量其他内容。

因此,我通常会说:小心模板!理想情况下,模板不应该在其实现代码中包含任何内容。

6

我跟着避免循环依赖一些最佳做法,

  1. 玉碎OOAD原则。除非包含的类与当前类具有合成关系,否则不要包含头文件。改用前向声明。
  2. 设计抽象类来充当两个类的接口。通过该接口进行类的交互。