【问题标题】:"X does not name a type" error in C++C ++中的“X没有命名类型”错误
【发布时间】:2011-01-09 03:33:03
【问题描述】:

我有两个类声明如下:

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

当我尝试使用 gcc 编译它时,它给出了以下错误:

MyMessageBox 没有命名类型

【问题讨论】:

  • 没完没了地出现这个错误,才意识到IDE生成的导入守卫是重复的
  • 请注意,如果在定义类之前在 .h / .hpp 文件中放置对声明的外部引用,即使在 .h 之后有实际声明,也会出现此错误/ .hpp 包含在 .cpp 文件中。
  • 您还应该始终使用命令 g++ 而不是 gcc 编译 C++ 文件

标签: c++ windows types


【解决方案1】:

当编译器编译类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);

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

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

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

【讨论】:

  • +1 今天学到了一些东西 - 我认为向前声明 MyMessageBox 就足够了。如果MyMessageBox 也有一个User 类型的变量怎么办?那会是死锁吗?
  • @Amargosh:是的,这是不可能的。逻辑上也是不可能的,因为User 会有一个MessageBox,它会有一个User,它会有一个MessageBox,它会有一个User,它会有一个MessageBox,它会有一个@ 987654348@,将有一个 MessageBox,将有一个 User...
【解决方案2】:
  1. 转发声明用户
  2. 将 MyMessageBox 的声明放在 User 之前

【讨论】:

    【解决方案3】:

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

    【讨论】:

    • 交换不起作用,因为 MyMessageBox 在其方法声明中有 User 类型。
    • 实际上,该定义并没有使用User。重要的区别,因为这意味着用户类只需要在那个时候声明,而不是定义。但请参阅 GMan 的大量帖子。
    • 是的,但是仅仅交换定义是行不通的,因为 User 类型尚未声明。
    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

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

      那也可以,因为 User 在 MyMessageBox 中被定义为指针

      【讨论】:

      • 前向声明是术语
      【解决方案6】:

      你必须在使用它之前声明它的原型:

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

      编辑:交换类型

      【讨论】:

      • 不,不会工作。必须定义类成员,而不是前向声明。
      【解决方案7】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-01
        • 2021-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多