C ++에서 "X는 유형의 이름을 지정하지 않습니다"오류


123

다음과 같이 선언 된 두 개의 클래스가 있습니다.

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

gcc를 사용하여 컴파일하려고하면 다음 오류가 발생합니다.

MyMessageBox는 유형의 이름을 지정하지 않습니다.



1
클래스가 정의되기 전에 .h / .hpp 파일에 선언에 대한 extern 참조를 배치하는 경우에도이 오류가 발생할 수 있습니다. .cpp 내에 .h / .hpp 포함 후 실제 선언이있는 경우에도 마찬가지입니다. 파일.
Owl

또한 항상 C ++ 파일을 명령이 g++아닌 명령으로 컴파일해야합니다gcc
Lorenzo Battilocchi

답변:


203

컴파일러가 클래스를 컴파일하고 행에 User도달하면 아직 정의되지 않았습니다. 컴파일러는 존재하지 않기 때문에 클래스 멤버의 의미를 이해할 수 없습니다.MyMessageBoxMyMessageBoxMyMessageBox

멤버로 사용 하기 전에이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;
}

앞으로 선언하여 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'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

14
@Amargosh : 네, 불가능합니다. 이후,뿐만 아니라 논리적으로 불가능 User있을 것 MessageBox있을 것이다 User, 어떤은 것 MessageBox을 것이다을 User, 어떤이있을 것 MessageBox있을 것이다 User하는이 것이다 MessageBox있을 것이다 User...
GManNickG


3

C ++ 컴파일러는 입력을 한 번 처리합니다. 사용하는 각 클래스가 먼저 정의되어 있어야합니다. 당신이 사용하는 MyMessageBox당신이 그것을 정의하기 전에. 이 경우 두 클래스 정의를 간단히 바꿀 수 있습니다.


로 작동하지 않습니다 스와핑 MyMessageBoxUser그것의 메서드 선언을 입력합니다.
Amarghosh

실제로 그 정의는 class를 사용 하지 않습니다 User. 중요한 차이점은 User 클래스 가 정의 되지 않고 해당 시점 에서만 선언 되어야 함을 의미하기 때문입니다 . 그러나 GMan의 광범위한 게시물을 참조하십시오.
MSalters

예,하지만 정의를 바꾸는 것은 User유형이 아직 선언되지 않았기 때문에 작동 하지 않습니다.
Amarghosh

3

User가 MyMessageBox의 객체를 값으로 포함하기 때문에 사용자보다 먼저 MyMessageBox를 정의해야 합니다 (따라서 컴파일러는 크기를 알아야합니다).

또한 MyMessageBox에는 User * 유형의 멤버가 포함되어 있으므로 MyMessageBox에 대해 사용자 를 전달 해야 합니다.


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에 포인터로 정의되어 있기 때문에 작동합니다.


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

1

C ++에서는 항상 헤더 파일 당 하나의 클래스를 사용하는 것이 좋습니다 . SO [ 1 ] 의이 토론을 참조하십시오 . GManNickG 답변은 왜 이런 일이 발생하는지 알려줍니다. 그러나이를 해결하는 가장 좋은 방법은 User클래스를 하나의 헤더 파일 ( User.h)에 배치하고 MyMessageBox클래스를 다른 헤더 파일 ( MyMessageBox.h)에 배치하는 것입니다. 그런 다음 당신 User.h이 포함 MyMessageBox.h하고 MyMessageBox.h당신 안에 User.h. 코드가 성공적으로 컴파일되도록 "include gaurds"[ 2 ]를 잊지 마십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.