2010-01-25 7 views
86

Tengo dos clases declaradas como a continuación:"no designa un tipo de" error

class User 
{ 
public: 
    MyMessageBox dataMsgBox; 
}; 

class MyMessageBox 
{ 
public: 
    void sendMessage(Message *msg, User *recvr); 
    Message receiveMessage(); 
    vector<Message> *dataMessageList; 
}; 

Cuando intenta compilar con gcc, se da el siguiente error:

MyMessageBox does not name a type

+10

Los tiempos infinitos me sale este error, solo para darme cuenta de que las guardias de importación generadas por el IDE están duplicadas – Mazyod

+0

Tenga en cuenta que también puede obtener este error si coloca una referencia externa a una declaración en un archivo .h/.hpp antes de que se defina la clase, incluso cuando tenga la declaración real después de la inclusión .h/.hpp dentro del archivo .cpp. – Owl

+0

@Mazyod. Gracias Gracias. No pude entender qué demonios estaba causando este extraño error. –

Respuesta

160

Cuando el compilador compila la clase User y llega a la línea MyMessageBox, MyMessageBox aún no se ha definido. El compilador no tiene idea MyMessageBox existe, por lo que no puede entender el significado de su miembro de la clase.

Debe asegurarse de MyMessageBox se define antes de lo utiliza como miembro. Esto se resuelve invirtiendo el orden de definición. Sin embargo, tiene una dependencia cíclica: si mueve MyMessageBox sobre User, entonces en la definición de MyMessageBox no se definirá el nombre User.

Lo que puedes hacer es delantero declararUser; es decir, declararlo pero no definirlo. Durante la compilación, un tipo declarado pero no definido se llama tipo incompleto. Considere el ejemplo más sencillo:

struct foo; // foo is *declared* to be a struct, but that struct is not yet defined 

struct bar 
{ 
    // this is okay, it's just a pointer; 
    // we can point to something without knowing how that something is defined 
    foo* fp; 

    // likewise, we can form a reference to it 
    void some_func(foo& fr); 

    // but this would be an error, as before, because it requires a definition 
    /* foo fooMember; */ 
}; 

struct foo // okay, now define foo! 
{ 
    int fooInt; 
    double fooDouble; 
}; 

void bar::some_func(foo& fr) 
{ 
    // now that foo is defined, we can read that reference: 
    fr.fooInt = 111605; 
    fr.foDouble = 123.456; 
} 

Por delante declarar User, MyMessageBox todavía se puede formar un puntero o referencia a ella:

class User; // let the compiler know such a class will be defined 

class MyMessageBox 
{ 
public: 
    // this is ok, no definitions needed yet for User (or Message) 
    void sendMessage(Message *msg, User *recvr); 

    Message receiveMessage(); 
    vector<Message>* dataMessageList; 
}; 

class User 
{ 
public: 
    // also ok, since it's now defined 
    MyMessageBox dataMsgBox; 
}; 

Usted no puede hacerlo al revés: como se ha mencionado, un miembro de la clase necesita tener una definición. (La razón es que el compilador necesita saber la cantidad de memoria User ocupa, y saber que lo que necesita saber el tamaño de sus miembros.) Si se va a decir:

class MyMessageBox; 

class User 
{ 
public: 
    // size not available! it's an incomplete type 
    MyMessageBox dataMsgBox; 
}; 

No funcionaría , ya que aún no conoce el tamaño.


En una nota lateral, esta función:

void sendMessage(Message *msg, User *recvr); 

probablemente no debería adoptar una de las de puntero. No puede enviar un mensaje sin un mensaje, ni puede enviar un mensaje sin un usuario para enviarlo. Y esas dos situaciones son expresables mediante el paso nulo como un argumento para cualquiera de los parámetros

Más bien, utilizar una referencia (posiblemente const) (nulo es un valor de puntero perfectamente válido!):

void sendMessage(const Message& msg, User& recvr); 
+1

+1 Aprendí algo hoy, creí que declarar 'MyMessageBox' hubiera sido suficiente. ¿Qué pasa si 'MyMessageBox' también tiene una variable de tipo' User', sería un punto muerto? – Amarghosh

+9

@Amargosh: Sí, sería imposible. Lógicamente imposible también, ya que 'User' tendría un' MessageBox' que tendría un 'User', que tendría un' MessageBox' que tendría un 'User', que tendría un' MessageBox' que tendría un ' User', que tendría un 'MessageBox' que tendría un' User' ... – GManNickG

+0

Gracias GMan. He hecho cambios a mi código como me sugirió y funciona bien ahora. –

0

Debe declarar el prototipo antes de usarlo:

class User; 

class MyMessageBox 
{ 
public: 
void sendMessage(Message *msg, User *recvr); 
Message receiveMessage(); 
vector<Message> *dataMessageList; 
}; 

class User 
{ 
public: 
MyMessageBox dataMsgBox; 
}; 

edición: cambiado el tipo

+1

No, no funcionará. Los miembros de la clase deben ser definidos, no declarados a la fuerza. – MSalters

2

compiladores de C++ procesan la ir entrada una vez. Cada clase que use debe haber sido definida primero. Utiliza MyMessageBox antes de definirlo. En este caso, puede simplemente cambiar las dos definiciones de clase.

+0

El intercambio no funcionará ya que 'MyMessageBox' tiene el tipo' Usuario' en su declaración de método. – Amarghosh

+0

No funciona porque MyMessageBox también usa la clase User. –

+0

En realidad, esa definición no _usa_ clase 'Usuario'. Importante distinción, porque eso significa que el usuario de clase solo necesita ser _declarado_ en ese punto, no _definido_. Pero vea la extensa publicación de GMan. – MSalters

6
  1. adelante declare usuario
  2. Ponga la declaración de MyMessageBox antes de usuario
2

Es necesario definir MyMessageBox antes de usuario - usuario porque incluye objetos de valor por MyMessageBox (y por lo compilador debe saber su tamaño).

También necesitará reenviar declarar Usuario antes de MyMessageBox - porque MyMessageBox incluye miembro de Usuario * tipo.

2

En una nota relacionada, si usted tenía:

class User; // let the compiler know such a class will be defined 

    class MyMessageBox 
    { 
    public: 
     User* myUser; 
    }; 

    class User 
    { 
    public: 
     // also ok, since it's now defined 
     MyMessageBox dataMsgBox; 
    }; 

entonces eso también trabajar, debido a que el usuario se define en MyMessageBox como un puntero

+0

Declaración directa es el término – benziv

0

Siempre se anima en C++ que tiene uno clase por archivo de encabezado, vea esta discusión en SO [1]. La respuesta de GManNickG dice por qué sucede esto. Pero la mejor manera de resolver esto es poner la clase User en un archivo de encabezado (User.h) y MyMessageBox clase en otro archivo de encabezado (MyMessageBox.h). Luego en su User.h incluye MyMessageBox.h y en MyMessageBox.h incluye User.h. No olvide "incluir gaurds" [2] para que su código compile con éxito.

Cuestiones relacionadas