Циклическая зависимость между заголовочными файлами - PullRequest
9 голосов
/ 18 января 2010

Я пытаюсь реализовать древовидную структуру с двумя классами: Tree и Node.Проблема в том, что из каждого класса я хочу вызвать функцию другого класса, поэтому простых предварительных объявлений недостаточно.

Давайте рассмотрим пример:

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

Thisэто простой пример, иллюстрирующий проблему.Поэтому я хочу вызвать функцию Tree из Node объекта.

Update # 1: Спасибо за ответы.Я пытался решить проблему, как в Java, то есть, используя только один файл на класс.Кажется, мне придется начать разделять файлы .cpp и .h ...

Обновление № 2: Ниже, следуя подсказкам, я также вставил полное решение.Спасибо, проблема решена.

Ответы [ 4 ]

5 голосов
/ 18 января 2010

В заголовках, вперед объявлять функции-члены:

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 голосов
/ 19 января 2010

Следуя подсказкам, вот полное решение.

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;
}
1 голос
/ 18 января 2010

Определение Tree требует определения Node, но не наоборот, поэтому ваше прямое объявление корректно.

Все, что вам нужно сделать, это удалить определение любых функций, которые требуютполное определение Tree из тела класса Node и реализация их в файле .cpp, где находятся полные определения обоих классов.

0 голосов
/ 18 января 2010

Можно ли использовать тела конструктора / деструктора в файле .cxx?Вы можете включить Tree.h туда.

...