2010-01-25 131 views
86

我必须声明,如下两类:“没有指定类型”的错误

class User 
{ 
public: 
    MyMessageBox dataMsgBox; 
}; 

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

当我尝试编译使用gcc,它提供了以下错误:

MyMessageBox does not name a type

+10

无尽的时间,我去这个错误,只是意识到由IDE生成的导入警卫重复 – Mazyod 2015-08-15 11:39:22

+0

请注意,如果您将一个外部引用声明放在.h/.hpp文件中也可以得到此错误在定义类之前,即使在.cpp文件中的.h/.hpp包含之后有实际的声明。 – Owl 2016-03-19 20:01:41

+0

@Mazyod。谢谢谢谢。我无法弄清楚是什么造成了这个奇怪的错误。 – 2017-02-10 19:13:04

回答

160

当编译器编译类User并进入MyMessageBox行,MyMessageBox尚未定义。编译器不知道MyMessageBox存在,所以不能理解你的类成员的含义。

您需要确保MyMessageBox被定义为之前您使用它作为成员。这是通过颠倒定义顺序来解决的。但是,您具有循环依赖关系:如果将MyMessageBox移动到User以上,则在MyMessageBox的定义中将不会定义名称User

您可以做的是正向声明User;即声明它,但不要定义它。在编译过程中,声明但未定义的类型称为不完整类型。 考虑简单的例子:

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

向前声明UserMyMessageBox仍然可以形成一个指针或引用它:

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

无法做到这一点的其他方式:如前所述,一个班级成员需要有一个定义。 (原因是编译器需要知道多少内存User如何占用了,要知道,它需要知道其成员的大小。)如果你是在说:

class MyMessageBox; 

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

这是行不通的,因为它还不知道尺寸。


在一个侧面说明,这样的功能:

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

也许不应该由指针采取这类原因。没有消息就不能发送消息,也不能发送没有用户发送消息的消息。而这两方面的情况是由空作为参数传递给任一参数表达

相反,使用引用(可能是const的)(null是一个完全有效的指针值!):

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

+1今天学到了一些东西 - 我认为向前声明MyMessageBox就足够了。如果'MyMessageBox'也有一个'User'类型的变量 - 那会是一个死锁吗? – Amarghosh 2010-01-25 15:38:57

+9

@Amargosh:是的,这是不可能的。在逻辑上也是不可能的,因为'User'会有一个'MessageBox',它有一个'User',它有一个'MessageBox',它有一个'User',它有一个'MessageBox',用户',这将有一个'MessageBox'这将有一个'用户'... – GManNickG 2010-01-25 15:41:36

+0

谢谢GMAN。我已经按照你的建议对我的代码进行了修改,现在它工作的很好。 – 2010-01-26 12:09:46

0

你必须申报使用前原型它:

class User; 

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

class User 
{ 
public: 
MyMessageBox dataMsgBox; 
}; 

编辑:交换了类型

+1

不,不会工作。班级成员必须定义,而不是被宣布。 – MSalters 2010-01-25 15:27:56

2

C++编译器处理所述ir输入一次。您使用的每个课程都必须先定义。您在定义它之前使用MyMessageBox。在这种情况下,您可以简单地交换两个类的定义。

+0

由于'MyMessageBox'在其方法声明中有'User'类型,交换将不起作用。 – Amarghosh 2010-01-25 15:33:56

+0

不工作,因为MyMessageBox也使用User类。 – 2010-01-25 15:39:24

+0

实际上,那个定义并没有_use_ class'User'。重要的区别,因为这意味着类用户只需在该点_declared_,而不是_defined_。但请参阅GMan广泛的帖子。 – MSalters 2010-01-26 08:46:12

6
  1. 正向声明用户
  2. 将MyMessageBox的声明之前用户
2

您需要用户之前定义MyMessageBox - 因为用户包括MyMessageBox 的对象由值(所以编译器应该知道它的大小)。

您还需要正向声明用户befor MyMessageBox - 因为MyMessageBox包含User *类型的成员。

2

与此相关的,如果你有:

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

那么这也将工作,因为用户在MyMessageBox定义为指针

+0

前向声明是该术语 – benziv 2017-07-13 01:14:11

0

它在C++中,你有一个总是鼓励每个头文件的类,参见SO [1]中的讨论。 GManNickG答案说明了为什么会发生这种情况。但解决此问题的最佳方法是将User类放在另一个头文件(MyMessageBox.h)中的一个头文件(User.h)和MyMessageBox类中。然后在您的User.h中包含MyMessageBox.h,并在MyMessageBox.h中包含User.h。不要忘记“包括gaurds”[2],以便您的代码编译成功。