C++ no me deja hacer amigos

5 minutos de lectura

Tengo dos clases, Mesh y MeshList. Quiero que MeshList tenga una función que pueda cambiar los miembros privados de Mesh. Pero no compilará y no sé por qué. Aquí está mi código.

Malla.h

#ifndef _MESH_H
#define _MESH_H

#include "MeshList.h"
#include <iostream>

class Mesh
{
private:
    unsigned int vboHandle_;
    friend void MeshList::UpdateVBOHandle();
public:
    inline void Out() {std::cout << vboHandle_;}
};
#endif

Malla.cpp

#include "Mesh.h"

MallaLista.h

#ifndef _MESH_LIST_H
#define _MESH_LIST_H

#include "Mesh.h"


class MeshList
{

public:
    Mesh *mesh; //Line 11 Error
    void UpdateVBOHandle();
};
#endif

MallaLista.cpp

#include "MeshList.h"

void MeshList::UpdateVBOHandle()
{
    *mesh->vboHandle_ = 4;
}

Me sale estos errores:

MeshList.h (Línea 11)

  • error C2143: error de sintaxis: falta ‘;’ antes de ‘*’
  • error C4430: falta el especificador de tipo – se asume int. Nota: C++ no es compatible con default-int
  • error C4430: falta el especificador de tipo – se asume int. Nota: C++ no es compatible con default-int

  • mesh.h(11): error C2653: ‘MeshList’: no ​​es un nombre de clase o espacio de nombres

  • meshlist.cpp(5): error C2248: ‘Mesh::vboHandle_’ : no se puede acceder al miembro privado declarado en la clase ‘Mesh’
  • mesh.h(10) : ver declaración de ‘Mesh::vboHandle_’
  • mesh.h(8): ver declaración de ‘Mesh’
  • meshlist.cpp(5): error C2100: direccionamiento indirecto ilegal

  • Necesitas salir más.

    – Mark Ransom

    27 de abril de 2012 a las 1:19

  • Probar class Meshlist; en vez de #include "MeshList.h"

    – chris

    27 de abril de 2012 a las 1:19


  • @Matthieu: sin embargo, un breve vistazo dice que es un muy buen comienzo.

    – Pato mugido

    27 de abril de 2012 a las 6:41

  • @MooingDuck: sí lo es, sin embargo, debido a que el OP intenta hacerse amigo de un solo método de MeshList una declaración hacia adelante no lo corta.

    – Matthieu M.

    27 de abril de 2012 a las 6:52

  • Ni siquiera leí esta pregunta antes de votar el comentario de @BenjaminLindley, y ahora estoy atrapado por ‘+1 solo por el título’.

    – Shep

    27 de abril de 2012 a las 6:54


cuando compilas Mesh.cppincluye Mesh.hque incluye MeshList.hque comienza a incluir Mesh.h pero se detiene temprano porque _MESH_H ahora está definido. Entonces (de vuelta en MeshList.h) hay una referencia a Mesh – pero eso no ha sido declarado todavía. Por lo tanto, por ejemplo, su error C2143.

  • @ildjarn, eso es interesante porque nunca lo descubrí en ninguna parte. ¿Puedo preguntar por qué?

    – chris

    27 de abril de 2012 a las 1:25

  • @chris: ¡Tendrías que preguntarle a la gente que diseñó C++!

    – ildjarn

    27 de abril de 2012 a las 1:26

  • @ildjarn: ¿Estás seguro? De hecho, estoy bastante seguro de que lo contrario es cierto. Incluso creo recordar que el estándar decía que hacerse amigo de una clase equivalía a hacerse amigo de todas sus funciones… Tendré que buscar la cita, supongo.

    – David Rodríguez – dribeas

    27 de abril de 2012 a las 1:32

  • @GarethMcCaughan Eliminé #include “MeshList.h” de Mesh.h, pero eso solo me da el error MeshList no es una clase o un espacio de nombres.

    – Legión

    27 de abril de 2012 a las 1:35

  • @Legion: tiene una dependencia cíclica, que generalmente son olores de código. En cualquier caso, si realmente cree que esto tiene sentido en su diseño, lo que debe hacer es adelante declarar la Mesh ante la definición de MeshList (que no necesita una definición completa del tipo) y luego incluya el encabezado Mesh solo en el .cpp.

    – David Rodríguez – dribeas

    27 de abril de 2012 a las 1:40

avatar de usuario
Esteban

Las dependencias cíclicas se explican en las otras respuestas …

Aquí viene la solución:

En MeshList.h:

  • reemplazar #include "Mesh.h" con la declaración anticipada class Mesh; (No necesita incluir aquí, porque solo declara un puntero a una malla)

En MeshList.cpp:

  • agregar #include "Mesh.h" a sus inclusiones (necesita la declaración, porque usa la Malla)

El último error de compilación que mencionaste es otro problema:

*mesh->vboHandle_ = 4;

mesh es un puntero. Tu código selecciona al miembro vboHandle_ e intenta desreferenciarlo (que falla). Supongo que te refieres a:

mesh->vboHandle_ = 4; // <-- no leading asterisk

  • Se corrigió la respuesta de acuerdo con el comentario de David.

    – Stephan

    2 mayo 2012 a las 15:43

avatar de usuario
Tajo domador

es porque has #include "MeshList.h" en el archivo Mesh.hpor lo que el archivo MeshList.h se compilará primero, y la clase Mesh aún no está declarado. Por eso el compilador pensará que Mesh en la línea de error hay un nombre de variable que no tiene un tipo antes, de ahí el error.

Este es un ejemplo de hacer un friend función miembro:

#include <iostream>


class foo;

class bar
{
public:
    void barfunc(foo &f);
};

class foo
{
private:
    friend void bar::barfunc(foo &f);
    int i;
public:
    foo()
    {
        i = 0;
    }
    void printi()
    {
        std::cout << i << '\n';
    }
};

void bar::barfunc(foo &f)
{
    f.i = 5;
}


int main()
{
    foo f;
    bar b;
    b.barfunc(f);
    f.printi();
    return 0;
}

El problema: Dependencias cíclicas en su include. El mensaje de error es menos que ideal, desafortunadamente.


La solución: Si se hace amigo de toda la clase, en lugar de una sola función, puede usar una declaración directa de la clase para romper el ciclo.

// Mesh.h
#ifndef _MESH_H
#define _MESH_H

#include <iostream>

class MeshList;

class Mesh
{
private:
    unsigned int vboHandle_;
    friend class MeshList;
public:
    inline void Out() {std::cout << vboHandle_;}
};
#endif

Algunas pautas (subjetivas):

  • Incluya cosas en orden inverso a su capacidad para cambiarlo si se rompe, es decir: STL primero, encabezados de terceros en segundo lugar, su propia pila de middleware tercero, el proyecto actual incluye el cuarto y la biblioteca actual incluye el quinto. De esta manera, si hay un conflicto, es de esperar que el error apunte a un encabezado tuyo.

  • Pon el public cosas antes de la private cosas en una clase. Los clientes de la clase solo se preocupan por la interfaz pública, no es necesario que revisen todos los detalles sucios de implementación antes de que puedan llegar a ella.

¿Ha sido útil esta solución?