node.h:

#include "tree_node.h"

class tree_node_t;
class node_base : public tree_node_t
{
public:
    node_base();
    ~node_base();
};

tree_node.h:

#include "node.h"

class node_base;
class tree_node_t
{
    tree_node_t();

    std::vector<node_base*> list;
    . . .
}

Todo parece estar correcto, pero por alguna razón me sale el error "uso no válido del tipo incompleto‘ class tree_node_t '". No entiendo por qué está sucediendo esto.

Según tengo entendido, la solución a estos problemas es dividir los archivos en encabezados (.h) y archivos de código fuente (.cpp). Dividido, pero sigue recibiendo tal error.

c++
-1
garbart 16 sep. 2018 a las 19:28

3 respuestas

La mejor respuesta

natersoz y Markus tenía razón. Todo lo que tenía que hacer era eliminar #include de tree_node.h.

0
garbart 16 sep. 2018 a las 17:25

No se puede heredar de un tipo incompleto. El compilador debe tener la definición completa de tree_node_t al heredar de él para determinar correctamente el tamaño de la clase, así como el desplazamiento de los miembros de datos.

Pero al poner class tree_node_t; después de haber incluido el encabezado, sombrea la definición que necesita el compilador. Entonces, solo quitando la línea class tree_node_t; debería hacer que todo compile bien, a menos que también te falten incluye guardias.

Como señaló correctamente Rudolfs Bundulis, también debe eliminar #include "node.h" en tree_node.h porque de lo contrario, el código que se pasa al compilador cuando se incluye tree_node.h tiene este aspecto:

class node_base : public tree_node_t
{
public:
  node_base();
  ~node_base();
 };

 class node_base;
 class tree_node_t
 {
   tree_node_t();

   std::vector<node_base*> list;
   . . .
 };

Que no se puede compilar porque de repente la definición de tree_node_t viene después de la definición de node_base que intenta heredar de ella.

1
Corristo 16 sep. 2018 a las 16:57

Según tengo entendido, la solución a estos problemas es dividir los archivos en encabezados (.h) y archivos de código fuente (.cpp).

Dividir el código en archivos suele ser la solución preferida. Al menos es algo bueno para que practiques.

En general, sin embargo, todavía se puede hacer este código en un solo archivo, y en este caso con una declaración de reenvío.

Las siguientes compilaciones, enlaces y ejecuciones (pero hace muy poco):


#include <iostream>
using std::cout, std::flush, std::endl;

#include <vector>
using std::vector;

// in this ordering, the single forward suffices,
//   because all class pointers are a known size,
// and
//    this symbol (as yet) is only in the tree_node_t data, 
//    in the vector as a pointer

class node_base_t;


class tree_node_t
{
   // private data attributes
   vector<node_base_t*> list;

   // tbd ... other data

public:
   tree_node_t()  // default ctor
   // : list ctor is ok
      {
         cout << "\n  tree_node_t() " << flush;
      }

   ~tree_node_t() = default; // dtor

   // tbd ... more public functions

private:
   // tbd ... private functions
};


class node_base_t : public tree_node_t
{
   // private data
   // ... tbd - other data
public:
   node_base_t()  // tree_node_t default ctor is ok
      {
         cout << "\n  node_base_t() " << flush;
      }

    ~node_base_t() = default;

   // tbd ... more public functions
private:
   // tbd ... private functions
};

int main(int , char** )
{
   int retVal = -1;
   {
      node_base_t  nb;

      retVal = 0;
   }
   cout << "\n" << endl;

   return retVal;
}

Salida:

  tree_node_t() 
  node_base_t() 
0
2785528 16 sep. 2018 a las 17:56