I have a small binary tree program spread over 4 files: main.cpp, tree.h, loop.h and node.h.
Inside the main.cpp file I include loop.h, inside loop.h I include arbol.h and inside arbol.h I include node.h
I just created a small function inside the Loop class of my loop.h file, which is a simple copy of the Sleep function from the windows.h library. I want to use this function within a member function of the Tree class that prints the nodes of the tree on the screen, that is, I want that every time a node is printed on the screen there is a wait of x seconds.
My error arises when I want to create a Loop class object within the Tree class or when I want to use inheritance, the compiler generates the error "Loop does not mean a type". So far I have tried simple inheritance, friend classes and friend methods. I also removed the function from the loop class and declared it inside the Tree class to test its correct operation.
I do not include details of the node.h file as it is just a class with the Node structure.
loop.h file
#ifndef LOOP_H
#define LOOP_H
#include<iostream>
using namespace std;
#include "arbol.h"
#include<time.h>
class Loop{
private:
Arbol Kyou; /*
Se crea un bojeto derivado de la clase Árbol,
este objeto lo utilizo para ejecutar las funciones
de la clase Arbol (como lo es crear un nuevo
nodo, buscar nodo, etc) dentro de mis funciones de
la clase Loop (como lo es pedir los datos del nodo,
etc)
E.g. void pedirDatos(){
cout << "Dame numero: ";
cin >> n;
Kyou.CrearNodo(n);
}
*/
public:
void esperar(float segundos){...}
/* Más funciones que no son importantes para el problema */
};
#endif
File tree.h
#ifndef ARBOL_H
#define ARBOL_H
#include "nodo.h"
#include "loop.h" /* Incluyo el archivo loop.h */
class Arbol{
private:
Nodo* Raiz;
int contador = 0;
Loop mano; /* El error es este */
public:
void MostrarArbol(){
mano.esperar(0.5); /* La función es de la clase Loop */
/* El proceso recursivo para mostrar el árbol */
}
};
#endif
The main.cpp file
#include<iostream>
using namespace std;
#include "loop.h"
int main(){
Loop l;
l.loop(); /* Función miembro de la clase Loop que genera todo el programa */
return 0;
}
One of the most common problems that you can face while programming in c++ is cross-references. In your case the header of
Loop
invokes the header ofArbol
and vice versa. And what happens is the following.This:
It becomes this:
Notice that now, inside
Arbol
, there is a reference to itself. Expanding that includes will not import Tree a second time, since that's what guards are for#ifndef
.What happens then is that in that file the declaration
Loop
tries to make use of the classArbol
, which is still unknown since it is declared later and hence the error.The solution to the problem is called declaration forward and it is based solely on telling the compiler: " look, there is a class (or structure or enumeration or function) that is called like this, I will give you more details in the future ". With this information, the compiler can now compile, although with certain limitations, as we will see later, we will leave the latter for later.
The case, how do you use a declaration forward ?
It's that simple:
What limitations does it have?
Since the compiler does not know the size of the class, it cannot be used by value. Pointers can only be declared:
As the compiler does not know the functions that this class implements either, it is not possible to make calls to member functions nor, of course, to
new
or adelete
, since these end up invoking the constructor and the destructor respectively:And, to top it off, since the compiler doesn't know the class's inheritance tree either, c++ casts (
dynamic_cast
) will also cause problems.In order to make use of all this functionality it is necessary for the compiler to know the class and this can only be achieved with the corresponding
#include
. Since we have already seen that we cannot add the dependency in the header file, the only solution is to move the#include
to the implementation file. Implementation files do not usually include references to other implementation files, so circular references will never occur in these files.NOTE: At this point, the problem you have regarding the other question in the thread is the following:
By adding that
#include
you are loading#define LOOP_H
, then when in the implementation file you call#include "loop.h" no se carga nada porque lo impiden las guardas (
#ifdef again LOOP_H` detects that the symbol is already defined).Your error is solved by removing the one
#include
from the header file:That error is because you are trying to use a type before declaring it.
According to the order of your
#include
declarations that the compiler sees are:The
#include
are literally put this file from this point . You use the classLoop
, in the tree.h file , before the compiler knows its type.You may think that you include
loop.h
withinarbol.h
, but its content is protected by the one#ifndef LOOP_H
at the beginning. Inmain.h
, by including it there, you define that symbol, so subsequent includes do nothing (logical thing, or you would have an include loop **.Another error your code throws: Class
Arbol
internally uses a classLoop
, internally uses a classArbol
, internally uses a classLoop
, ... it hasn't shown you yet, because it complains about missing a type, but it will.To figure it all out, you have to predeclare the class
Loop
. In the fileArbol.h
, you have to add a line:With that, the compiler already knows that it
Loop
is a class.To solve the loop in the class definition, one of them has to stop using
instancias
the other, and replace them with pointers or references