Ошибка "не указывать тип"

У меня есть два класса, объявленные ниже:

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

Когда я пытаюсь скомпилировать его с помощью gcc, он дает следующую ошибку:

MyMessageBox не называет тип

Ответ 1

Когда компилятор компилирует класс User и попадает в строку MyMessageBox, MyMessageBox еще не определен. Компилятор понятия не имеет MyMessageBox существует, поэтому не может понять смысл вашего члена класса.

Вам необходимо убедиться, что MyMessageBox определен, прежде чем использовать его в качестве члена. Это решается путем изменения порядка определения. Однако у вас есть циклическая зависимость: если вы перемещаете MyMessageBox выше User, тогда в определении MyMessageBox имя User не будет определено!

Что вы можете сделать, это forward declare User; то есть объявить его, но не определять. Во время компиляции тип, объявленный, но не определенный, называется неполным. Рассмотрим более простой пример:

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

struct bar
{
    // this is okay, it 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;
}

Переходя объявлением User, MyMessageBox может по-прежнему формировать указатель или ссылку на него:

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 now defined
    MyMessageBox dataMsgBox;
};

Вы не можете сделать это наоборот: как уже упоминалось, член класса должен иметь определение. (Причина в том, что компилятор должен знать, сколько занимает память User, и знать, что ему нужно знать размер его членов.) Если бы вы сказали:

class MyMessageBox;

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

Это не сработает, так как пока не знает размер.


На боковой ноте эта функция:

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

Вероятно, не следует брать ни один из указателей. Вы не можете отправить сообщение без сообщения, а также не можете отправить сообщение без отправки его пользователю. И обе эти ситуации можно выразить, передав null в качестве аргумента для любого параметра (null - это абсолютно допустимое значение указателя!)

Скорее используйте ссылку (возможно, const):

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

Ответ 2

  • Вперед объявить пользователя
  • Поместите объявление MyMessageBox перед пользователем

Ответ 3

Компиляторы С++ обрабатывают свой ввод один раз. Каждый класс, который вы используете, должен быть определен первым. Вы используете MyMessageBox, прежде чем определять его. В этом случае вы можете просто заменить два определения класса.

Ответ 4

Вам нужно определить 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 now defined
        MyMessageBox dataMsgBox;
    };

Тогда это также сработает, потому что Пользователь определен в MyMessageBox как указатель

Ответ 6

Вы должны объявить прототип перед его использованием:

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

изменить: изменили типы

Ответ 7

В С++ всегда рекомендуется, чтобы у вас был один класс в файле заголовка, см. это обсуждение в SO [1]. Ответ GManNickG подсказывает, почему это происходит. Но лучший способ решить это - поставить класс User в один заголовочный файл (User.h) и MyMessageBox в другой заголовочный файл (MyMessageBox.h). Затем в User.h вы включаете MyMessageBox.h, а в MyMessageBox.h включаете User.h. Не забудьте "включить gaurds" [2], чтобы ваш код успешно компилировался.