头文件之间的循环依赖

Posted

技术标签:

【中文标题】头文件之间的循环依赖【英文标题】:Cyclic dependency between header files 【发布时间】:2011-01-06 12:56:33 【问题描述】:

我正在尝试实现具有两个类的树状结构:TreeNode。问题是我想从每个类中调用另一个类的函数,所以简单的前向声明是不够的。

我们来看一个例子:

Tree.h:

#ifndef TREE_20100118
#define TREE_20100118

#include <vector>
#include "Node.h"

class Tree

    int counter_;
    std::vector<Node> nodes_;

public:

    Tree() : counter_(0) 

    void start() 
        for (int i=0; i<3; ++i) 
            Node node(this, i);
            this->nodes_.push_back(node);
        
        nodes_[0].hi();    // calling a function of Node
    

    void incCnt() 
        ++counter_;
    

    void decCnt() 
        --counter_;
    

;

#endif /* TREE_20100118 */

Node.h:

#ifndef NODE_20100118
#define NODE_20100118

#include <iostream>
//#include "Tree.h"

class Tree;    // compile error without this

class Node

    Tree * tree_;
    int id_;

public:

    Node(Tree * tree, int id) : tree_(tree), id_(id)
    
//      tree_->incCnt();    // trying to call a function of Tree
    

    ~Node() 
//      tree_->decCnt();    // problem here and in the constructor
    

    void hi() 
        std::cout << "hi (" << id_ << ")" << endl;
    

;

#endif /* NODE_20100118 */

调用树:

#include "Tree.h"
...
Tree t;
t.start();

这只是一个简单的例子来说明问题。所以我想要的是从Node 对象调用Tree 的函数。

更新 #1: 感谢您的回答。我试图像在 Java 中那样解决这个问题,即每个类只使用一个文件。看来我得开始分离 .cpp 和 .h 文件了……

更新 #2: 在下面,按照提示,我也粘贴了完整的解决方案。谢谢,问题解决了。

【问题讨论】:

【参考方案1】:

在头文件中,前向声明成员函数:

class Node

    Tree * tree_;
    int id_;

public:
    Node(Tree * tree, int id);
    ~Node();
    void hi();
;

在包含所有必需标头的单独 .cpp 文件中,定义它们:

#include "Tree.h"
#include "Node.h"

Node::Node(Tree * tree, int id) : tree_(tree), id_(id)

  tree_->incCnt();


Node::~Node() 

  tree_->decCnt();


etc

这也有保持你的标题可读的效果,所以很容易一目了然地看到一个类的接口。

【讨论】:

【参考方案2】:

按照提示,这里是完整的解决方案。

Tree.h:

#ifndef TREE_20100118
#define TREE_20100118

#include "Node.h"
#include <vector>

class Tree

    int counter_;
    std::vector<Node> nodes_;

public:

    Tree();
    void start();
    void incCnt();
    void decCnt();
;

#endif /* TREE_20100118 */

Tree.cpp:

#include "Tree.h"
#include "Node.h"

Tree::Tree() : counter_(0) 

void Tree::start()

    for (int i=0; i<3; ++i) 
        Node node(this, i);
        this->nodes_.push_back(node);
    
    nodes_[0].hi();    // calling a function of Node


void Tree::incCnt() 
    ++counter_;


void Tree::decCnt() 
    --counter_;


Node.h:

#ifndef NODE_20100118
#define NODE_20100118

class Tree;

class Node

    Tree * tree_;
    int id_;

public:

    Node(Tree * tree, int id);
    ~Node();
    void hi();
;

#endif /* NODE_20100118 */

Node.cpp:

#include "Node.h"
#include "Tree.h"

#include <iostream>

Node::Node(Tree * tree, int id) : tree_(tree), id_(id)

    tree_->incCnt();    // calling a function of Tree


Node::~Node() 
    tree_->decCnt();


void Node::hi() 
    std::cout << "hi (" << id_ << ")" << std::endl;

【讨论】:

【参考方案3】:

Tree 的定义需要Node 的定义,但反之则不然,因此您的前向声明是正确的。

您所要做的就是从Node 类主体中删除需要完整定义Tree 的任何函数的定义,并在.cpp 文件中实现它们,其中两个类的完整定义都在范围内.

【讨论】:

【参考方案4】:

你能把构造函数/析构函数放在 .cxx 文件中吗?您可以在其中包含 Tree.h。

【讨论】:

以上是关于头文件之间的循环依赖的主要内容,如果未能解决你的问题,请参考以下文章

解决由于类之间的循环依赖而导致的构建错误

解决由于类之间的循环依赖而导致的构建错误

解决由于类之间的循环依赖而导致的构建错误

解决由于类之间的循环依赖而导致的构建错误

如何解决这种循环依赖?

F#中不同文件的类型和函数之间的循环依赖问题