Do you have any good advice on how to avoid circular dependencies of header files, please?
Of course, from the beginning, I try to design the project as transparent as possible. However, as more and more features and classes are added, and the project gets less transparent, circular dependencies start happening.
Are there any general, verified, and working rules? Thanks.
If you have circular dependency then you doing something wrong.
As for example:
foo.h
-----
class foo {
public:
bar b;
};
bar.h
-----
class bar {
public:
foo f;
};
Is illegal you probably want:
foo.h
-----
class bar; // forward declaration
class foo {
...
bar *b;
...
};
bar.h
-----
class foo; // forward declaration
class bar {
...
foo *f;
...
};
And this is ok.
General rules:
- Make sure each header can be included on its own.
- If you can use forward declarations use them!
- Use forward declarations where possible.
- Move any header includes out of a header file and into the corresponding cpp file if they are only needed by the cpp file. Easiest way to enforce this is to make the
#include "myclass.h"
the first include inmyclass.cpp
. - Introducing interfaces at the point of interaction between separate classes can help reduce dependencies.
Some best practices I follow to avoid circular dependencies are,
- Stick to OOAD principles. Don't include a header file, unless the class included is in composition relationship with the current class. Use forward declaration instead.
- Design abstract classes to act as interfaces for two classes. Make the interaction of the classes through that interface.
A general approach is to factor out the commonalities into a third header file which is then referenced by the two original header files.
See also Circular Dependency Best Practice
depending on your preprocessor capabilities:
#pragma once
or
#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif
If you find it very boring to design header files maybe makeheaders from Hwaci (designers of SQLite and fossil DVCS) could be of interest for you.
What you're aiming at is a layered approach. You can define layers where modules can depend on lower layer modules but the inverse should be done with observers. Now you can still define how fine-grained your layers should be and whether you accept circular dependency within layers, but in this case I would use this.
In general header files should forwardly declare rather than include other headers wherever possible.
Also ensure you stick to one class per header.
Then you almost certainly will not go wrong.
The worst coupling usually comes from bloated template code. Because you have to include the definition inside the header, it often leads to all kinds headers having to be included, and then the class that uses the template includes the template header, including a load of other stuff.
For this reason, I would generally say: be careful with templates! Ideally a template should not have to include anything in its implementation code.
Altough Artyom provided best answer this tutorial is also great and provides some extenstions http://www.cplusplus.com/forum/articles/10627/
精彩评论