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
अंतहीन समय मैं यह त्रुटि हो जाती है, बस यह महसूस करने के लिए कि आईडीई द्वारा आयात किए गए आयात गार्ड डुप्लिकेट किए गए हैं
Mazyod

1
ध्यान दें कि यदि आप कक्षा में परिभाषित होने से पहले .h / .hpp फ़ाइल में घोषणा के लिए बाहरी संदर्भ देते हैं, तो भी आपको यह त्रुटि मिल सकती है, जब आपके पास .c / .hpp समावेश के बाद वास्तविक घोषणा .cc के भीतर हो। फ़ाइल।
उल्लू

आपको हमेशा C ++ फ़ाइलों को कमांड के साथ संकलित करना चाहिए g++और नहींgcc
लोरेंजो बैटिलिकोची

जवाबों:


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

आगे की घोषणा करके 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);

संभवतः सूचक द्वारा उन दोनों में से कोई भी नहीं लेना चाहिए। आप एक संदेश के बिना एक संदेश नहीं भेज सकते हैं, और न ही आप इसे भेजने के लिए एक उपयोगकर्ता के बिना एक संदेश भेज सकते हैं। और उन दोनों स्थितियों को या तो पैरामीटर के लिए एक तर्क के रूप में अशक्त पारित करके व्यक्त किया जाता है (अशक्त पूरी तरह से वैध सूचक मान है!)।

बल्कि, एक संदर्भ (संभवतः कास्ट) का उपयोग करें:

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

3
+1 आज कुछ सीखा - मैंने सोचा कि घोषणा MyMessageBoxकरना पर्याप्त होगा। क्या होगा यदि MyMessageBoxप्रकार का एक चर Userभी था - क्या यह गतिरोध होगा?
अमरघोष

14
@Amargosh: हाँ, यह असंभव होगा। तार्किक रूप से असंभव के रूप में अच्छी तरह से, के बाद से Userएक है MessageBoxजो एक होगा User, जो एक होता है एक MessageBoxहोता है User, जो एक MessageBoxहोता है User, जो एक होता है , जो एक MessageBoxहोता है User...
GManNickG


3

C ++ कंपाइलर एक बार अपने इनपुट को प्रोसेस करते हैं। आपके द्वारा उपयोग किए जाने वाले प्रत्येक वर्ग को पहले परिभाषित किया गया होगा। आप MyMessageBoxइसे परिभाषित करने से पहले उपयोग करते हैं। इस स्थिति में, आप बस दो श्रेणी की परिभाषाएँ स्वैप कर सकते हैं।


स्वैपिंग काम नहीं करेगी क्योंकि MyMessageBoxइसमें Userविधि घोषणा है।
अमरघोष

दरअसल, वह परिभाषा कक्षा का उपयोग नहीं करती है User। महत्वपूर्ण अंतर, क्योंकि इसका मतलब है कि वर्ग उपयोगकर्ता को केवल उस बिंदु पर घोषित करने की आवश्यकता है , परिभाषित नहीं । लेकिन GMan की व्यापक पोस्ट देखें।
MSalters

हाँ, लेकिन केवल परिभाषाओं को स्वैप करने से काम नहीं चलेगा क्योंकि Userप्रकार अभी तक घोषित नहीं किया गया है।
अमरघोष

3

आपको उपयोगकर्ता से पहले MyMessageBox को परिभाषित करने की आवश्यकता है - क्योंकि उपयोगकर्ता में मूल्य द्वारा MyMessageBox की वस्तु शामिल है (और इसलिए संकलक को इसका आकार जानना चाहिए)।

इसके अलावा, आपको आगे की घोषणा करने की आवश्यकता होगी उपयोगकर्ता befor MyMessageBox - क्योंकि 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
फॉरवर्ड डिक्लेरेशन शब्द है
बेन्ज़िव जूल

1

उपयोग करने से पहले आपको इसे प्रोटोटाइप घोषित करना होगा:

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

संपादित करें : प्रकार स्वैप किए गए


1
नहीं, काम नहीं करेगा। वर्ग के सदस्यों को परिभाषित किया जाना चाहिए, न कि पूर्व घोषित।
MSalters

1

यह C ++ में हमेशा प्रोत्साहित किया जाता है कि आपके पास एक हेडर फ़ाइल प्रति वर्ग है, इस चर्चा को SO [ 1 ] में देखें। GManNickG का उत्तर बताता है कि ऐसा क्यों होता है। लेकिन इसे हल करने का सबसे अच्छा तरीका Userक्लास को एक हेडर फ़ाइल ( User.h) में और MyMessageBoxक्लास को किसी अन्य हेडर फ़ाइल ( MyMessageBox.h) में रखना है । फिर आपके में User.hआप शामिल हैं MyMessageBox.hऔर MyMessageBox.hआप में शामिल हैं User.h। "गोरस को शामिल करें" [ 2 ] मत भूलना ताकि आपका कोड सफलतापूर्वक संकलित हो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.