C ++中的“ X未命名类型”错误


123

我有两个声明如下的类:

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

当我尝试使用gcc进行编译时,出现以下错误:

MyMessageBox没有命名类型


16
我无休止地走出这个错误,只是想知道由IDE生成的导入保护是重复的
Mazyod 2015年

1
请注意,如果在定义类之前在.h / .hpp文件中放置了对声明的外部引用,即使在.cpp中包含.h / .hpp的实际声明之后,也可能会出现此错误。文件。
猫头鹰

您还应该始终使用命令g++而不是使用命令来编译C ++文件gcc
Lorenzo Battilocchi,

Answers:


203

当编译器编译该类User并到达该MyMessageBox行时,MyMessageBox尚未定义。编译器不知道MyMessageBox存在,所以无法理解类成员的含义。

将其用作成员之前,需要确保MyMessageBox已定义。这可以通过反转定义顺序来解决。但是,您有一个循环依赖项:如果您移至上方,则将不会定义名称!MyMessageBoxUserMyMessageBoxUser

您可以做的是向前声明 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);

可能不应该通过指针来获取任何一个。您不能在没有消息的情况下发送消息,也不能在没有用户发送消息的情况下发送消息。这两种情况都可以通过将null作为参数传递给任一参数来表示(null是一个完全有效的指针值!)

而是使用引用(可能是const):

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

3
+1今天学到了一些东西-我认为向前声明MyMessageBox就足够了。如果MyMessageBox也有类型变量,User那会是一个死锁吗?
Amarghosh 2010年

14
@Amargosh:是的,这不可能。逻辑上也是不可能的,因为User将有一个MessageBox将具有一个User,将具有一个MessageBox将具有一个User,将具有一个MessageBox将具有一个User,将具有一个MessageBox将具有一个User...
GManNickG 2010年


3

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


交换将无法正常工作MyMessageBoxUser它的方法声明类型。
Amarghosh 2010年

实际上,该定义不使用 class User。重要区别,因为这意味着只需要在那时声明 User类,而不需要定义。但是请参阅GMan的广泛文章。
MSalters 2010年

是的,但是简单地交换定义将不起作用,因为User尚未声明类型。
Amarghosh

3

您需要在User之前定义MyMessageBox -因为User 通过值包含MyMessageBox 对象(因此编译器应该知道其大小)。

另外,您还需要在MyMessageBox之前转发声明用户-因为MyMessageBox包含User *类型的成员。


3

在相关说明中,如果您有:

    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中将User定义为指针


1
前瞻性声明是术语
benziv

1

您必须先声明原型,然后再使用它:

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

编辑:交换类型


1
不,不行。必须定义类成员,而不声明forqward。
MSalters 2010年

1

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.