2012-04-27 10 views
29

Ho due classi, Mesh e MeshList. Voglio MeshList per avere una funzione che può cambiare i membri privati ​​di Mesh. Ma non verrà compilato e non so perché. Ecco il mio codice.C++ non mi permette di fare amicizia

Mesh.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 

Mesh.cpp

#include "Mesh.h" 

MeshList.h

#ifndef _MESH_LIST_H 
#define _MESH_LIST_H 

#include "Mesh.h" 


class MeshList 
{ 

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

MeshList.cpp

#include "MeshList.h" 

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

ottengo questi errori:

MeshList.h (Linea 11)

  • errore C2143: errore di sintassi: manca ';' prima di '*'
  • errore C4430: identificatore di tipo mancante - int assunto. Nota: C++ no supporto predefinito-int
  • errore C4430: identificatore di tipo mancante - int assunto. Nota: C++ non supporto

  • mesh.h default-int (11): l'errore C2653: 'MeshList': non è una classe o spazio dei nomi nome

  • meshlist.cpp (5): l'errore C2248 : 'Mesh :: vboHandle_': non può accedere membro privato dichiarato nella classe 'mesh'
  • mesh.h (10): vedi dichiarazione di 'Mesh :: vboHandle_'
  • mesh.h (8): vedi dichiarazione di 'Mesh'
  • meshlist.cpp (5): errore C2100: indiretto illegale
+38

Hai bisogno di uscire di più. –

+32

+1 per il solo titolo. –

+5

Prova 'class Meshlist;' invece di '#include" MeshList.h "' – chris

risposta

6

dipendenze cicliche sono spiegate nelle altre risposte ...

Arriva la soluzione:

In MeshList.h:

  • sostituire #include "Mesh.h" con la dichiarazione anticipata class Mesh; (È don 'necessario l'inclusione qui, perché si dichiara un puntatore solo a una mesh)

In MeshList.cpp:

  • aggiungere #include "Mesh.h" al vostro include (è necessario la dichiarazione, perché si utilizza la Mesh)

L'ultimo errore di compilazione, è menzionato è un altro problema:

*mesh->vboHandle_ = 4; 

mesh è un puntatore. Il tuo codice seleziona il membro vboHandle_ e prova a dereferenziarlo (che non riesce). Suppongo che tu voglia dire:

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

Risolto il problema in base al commento di David. – Stephan

9

Quando si compila Mesh.cpp, include Mesh.h, che comprende MeshList.h, che inizia ad includere Mesh.h ma si ferma presto perché _MESH_H è ora definita. Quindi (di nuovo in MeshList.h) c'è un riferimento a Mesh - ma non è stato ancora dichiarato. Quindi, ad esempio, l'errore C2143.

+0

@ildjarn, è interessante perché non l'ho mai scoperto da nessuna parte. Posso chiedere perchè? – chris

+0

@chris: Dovresti chiedere alle persone che hanno progettato C++! – ildjarn

+0

@ildjarn: sei sicuro?In realtà sono abbastanza sicuro che è vero il contrario. Penso persino di ricordare che lo standard affermava che fare amicizia con una classe equivaleva a fare amicizia con tutte le sue funzioni ... Dovrò cercare la citazione che immagino. –

6

È perché hai #include "MeshList.h" nel file Mesh.h, quindi il file MeshList.h verrà compilato prima, e la classe Mesh non è ancora dichiarato. Per quello il compilatore penserà che Mesh nella riga di errore è un nome di variabile che non ha un tipo prima di esso, quindi l'errore.

Questo è un esempio di fare una funzione di membro friend:

#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; 
} 
4

il problema: dipendenze cicliche nella vostra include. Il messaggio di errore non è ideale, sfortunatamente.


La soluzione: Se amicizia con tutta la classe, invece di una singola funzione, quindi è possibile utilizzare una dichiarazione anticipata della classe per rompere il 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 

Alcuni (soggettivo) le linee guida:

  • includendo cose in ordine inverso della vostra capacità di cambiarlo se si rompe, vale a dire: STL prima, 3rd intestazioni di partito secondo, il tuo proprio stack middleware terzo, il progetto corrente include il quarto e la libreria corrente include quinto. In questo modo, se c'è un conflitto, si spera che l'errore indicherà una tua intestazione.

  • Inserire la roba public prima della roba private in una classe. I clienti della classe si occupano solo dell'interfaccia pubblica, non c'è bisogno di farli passare attraverso tutti i dettagli di implementazione sporchi prima che possano accedervi.

+0

Come ho capito, non è necessario inoltrare dichiarazione se la dichiarazione del tuo amico è superiore al primo utilizzo. (Ho provato un esempio simile con la classe MeshList; "in VS e funziona.) – anxieux

+0

@anxieux: Non ho mai veramente capito in quale ambito il nome dopo' friend class' è stato iniettato se non è stato trovato; quindi ho preso l'abitudine di andare avanti dichiarando il tipo. Leggermente più verboso, forse, ma hey: funziona al 100% del tempo! –

Problemi correlati