【发布时间】:2011-06-16 13:06:08
【问题描述】:
您对如何避免头文件的循环依赖有什么好的建议吗?
当然,从一开始,我就尝试将项目设计得尽可能透明。然而,随着越来越多的特性和类被添加,项目变得越来越不透明,循环依赖开始出现。
是否有任何通用的、经过验证的和有效的规则?谢谢。
【问题讨论】:
标签: c++ software-design architecture
您对如何避免头文件的循环依赖有什么好的建议吗?
当然,从一开始,我就尝试将项目设计得尽可能透明。然而,随着越来越多的特性和类被添加,项目变得越来越不透明,循环依赖开始出现。
是否有任何通用的、经过验证的和有效的规则?谢谢。
【问题讨论】:
标签: c++ software-design architecture
如果你有循环依赖,那么你做错了什么。
例如:
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;
...
};
这没关系。
一般规则:
【讨论】:
scoped_ptr 或unique_ptr。如果指针只是对对象的引用,那么可能有必要使用观察者模式,以便在所引用的对象被销毁时“取消设置”。
auto_ptr,当您不想依赖boost 或C++0x 时更好)。但我更想展示一般的想法而不是实时代码。如果 foo 有前向声明,它甚至可能是 std::vector<foo>。
auto_ptr,这样更糟。如果需要,可以从 boost 中删除 scoped_ptr 的代码,但是 auto_ptr 带来了太多的惊喜(在复制/分配时)。
#include "myclass.h" 成为myclass.cpp 中的第一个包含。【讨论】:
我遵循的一些避免循环依赖的最佳实践是,
【讨论】:
一般的做法是将共性分解到第三个头文件中,然后由两个原始头文件引用。
【讨论】:
取决于您的预处理器功能:
#pragma once
或
#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif
如果你觉得设计头文件很无聊,也许你可能会对来自 Hwaci(SQLite 和化石 DVCS 的设计者)的 makeheaders 感兴趣。
【讨论】:
您的目标是 layered approach。您可以定义模块可以依赖于较低层模块的层,但应使用 observers 完成相反的操作。现在你仍然可以定义你的层应该有多细以及你是否接受层内的循环依赖,但在这种情况下我会使用this。
【讨论】:
一般来说,头文件应该向前声明,而不是尽可能包含其他头文件。
还要确保每个标题都坚持一个类。
那么你几乎肯定不会出错。
最糟糕的耦合通常来自于臃肿的模板代码。因为你必须在头文件中包含定义,这通常会导致必须包含各种头文件,然后使用模板的类包含模板头,包括大量其他内容。
出于这个原因,我通常会说:小心使用模板!理想情况下,模板不应该在其实现代码中包含任何内容。
【讨论】:
Altough Artyom 提供了最佳答案,本教程也很棒,并提供了一些扩展 http://www.cplusplus.com/forum/articles/10627/
【讨论】: