Циклическая зависимость между заголовочными файлами

Я пытаюсь реализовать древовидную структуру с двумя классами: 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();

Это - просто простой пример для иллюстрирования проблемы. Таким образом, то, что я хочу, вызывает функцию Tree от a Node объект.

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

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

9
задан Lii 24 May 2018 в 22:56
поделиться

4 ответа

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

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

Это также позволяет сохранить ваши заголовки читаемыми, так что легко увидеть интерфейс класса с первого взгляда.

5
ответ дан 3 November 2019 в 03:47
поделиться

После подсказки вот полное решение.

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;
}
2
ответ дан 3 November 2019 в 03:47
поделиться

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

0
ответ дан 3 November 2019 в 03:47
поделиться

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

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

Это также позволяет сохранить ваши заголовки читаемыми, так что легко увидеть интерфейс класса.

-121--3383578-

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

-121--3383581-

Определение дерева требует определения узла , но не других путей, поэтому ваше объявление о пересылке является правильным.

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

1
ответ дан 3 November 2019 в 03:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: