Dipendenza ciclica tra i file di intestazione

Sto cercando di implementare una struttura ad albero con due classi: Tree e Node . Il problema è che da ogni class voglio chiamare una funzione dell’altra class, quindi le semplici dichiarazioni di avanzamento non sono sufficienti.

Vediamo un esempio:

Tree.h:

 #ifndef TREE_20100118 #define TREE_20100118 #include  #include "Node.h" class Tree { int counter_; std::vector nodes_; public: Tree() : counter_(0) {} void start() { for (int i=0; inodes_.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  //#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 */ 

Calling Tree:

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

Questo è solo un semplice esempio per illustrare il problema. Quindi quello che voglio è chiamare una funzione di Tree da un object Node .

Aggiornamento n. 1: grazie per le risposte. Ho provato a risolvere il problema come in Java, cioè usando solo un file per class. Sembra che dovrò iniziare a separare file .cpp e .h …

Aggiornamento n. 2: di seguito, seguendo i suggerimenti, ho incollato anche la soluzione completa. Grazie, problema risolto.

Nelle intestazioni, inoltrare le funzioni membro:

 class Node { Tree * tree_; int id_; public: Node(Tree * tree, int id); ~Node(); void hi(); }; 

In un file .cpp separato che include tutti gli header richiesti, definiscili:

 #include "Tree.h" #include "Node.h" Node::Node(Tree * tree, int id) : tree_(tree), id_(id) { tree_->incCnt(); } Node::~Node() { tree_->decCnt(); } etc 

Ciò ha anche l’effetto di mantenere leggibili le intestazioni, quindi è facile vedere l’interfaccia di una class a colpo d’occhio.

Seguendo i suggerimenti, ecco la soluzione completa.

Tree.h:

 #ifndef TREE_20100118 #define TREE_20100118 #include "Node.h" #include  class Tree { int counter_; std::vector 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  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; } 

La definizione di Tree richiede la definizione di Node ma non il contrario, quindi la tua dichiarazione di forward è corretta.

Tutto ciò che devi fare è rimuovere la definizione di tutte le funzioni che richiedono una definizione completa di Tree dal corpo della class Node e implementarle in un file .cpp cui sono presenti le definizioni complete di entrambe le classi.

Puoi fare a meno del corpo del costruttore / distruttore in un file .cxx? Potresti includere Tree.h lì.