代码之家  ›  专栏  ›  技术社区  ›  Jabba

头文件之间的循环依赖关系

  •  9
  • Jabba  · 技术社区  · 15 年前

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

    让我们看一个例子:

    树:

    #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 */
    

    节点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();
    

    这只是一个简单的例子来说明这个问题。所以我想要的是调用 从A 结点 对象。

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

    更新第2号: 下面,根据提示,我也粘贴了完整的解决方案。谢谢,问题解决了。

    4 回复  |  直到 7 年前
        1
  •  5
  •   moonshadow    15 年前

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

    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
  •  2
  •   Jabba    15 年前

    根据提示,这里是完整的解决方案。

    树:

    #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_;
    }
    

    节点:

    #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
  •  1
  •   CB Bailey    15 年前

    定义 Tree 需要定义 Node 但不是相反,所以你的远期声明是正确的。

    您所要做的就是删除需要完整定义 结点 类主体并在 .cpp 两个类的完整定义都在作用域中的文件。

        4
  •  0
  •   Richard Pennington    15 年前

    除了.cxx文件中的构造器/析构函数体之外,您还可以吗?你可以把树也包括进去。

    推荐文章