C ++ 'da "X bir türü adlandırmıyor" hatası


124

Aşağıdaki gibi iki sınıfım var:

class User
{
public:
  MyMessageBox dataMsgBox;
};

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

Gcc kullanarak derlemeye çalıştığımda şu hatayı veriyor:

MyMessageBox bir türü adlandırmıyor


17
IDE tarafından üretilen ithalat korumalarının çoğaltıldığını fark etmek için bu hatayı sonsuz kez yapıyorum
Mazyod

1
Cpp içinde .h / .hpp eklemesinden sonra gerçek bildirime sahip olsanız bile, sınıf tanımlanmadan önce .h / .hpp dosyasındaki bir bildirime bir extern başvurusu yerleştirirseniz, bu hatayı da alabileceğinizi unutmayın. dosya.
Baykuş

Ayrıca her zaman komutla C ++ dosyaları derlemek gerekir g++değilgcc
Lorenzo Battilocchi

Yanıtlar:


204

Derleyici sınıfı derlediğinde Userve MyMessageBoxsatıra geldiğinde , MyMessageBoxhenüz tanımlanmamıştır. Derleyicinin hiçbir fikri MyMessageBoxyoktur, bu nedenle sınıf üyenizin anlamını anlayamaz.

Daha önceMyMessageBox tanımlandığından emin olmalısınÜye olarak kullanmadan . Bu, tanım sırasını tersine çevirerek çözülür. Ancak, bir döngüsel bağımlılığı: Eğer taşırsanız MyMessageBoxyukarıdaki Usersonra tanımındaki MyMessageBoxadı Usertanımlanamaz olacak!

Yapabilecekleriniz ileriye doğru beyan etmektir User ; yani ilan edin ama tanımlamayın. Derleme sırasında, bildirilen ancak tanımlanmayan bir türe tamamlanmamış tür denir . Daha basit örneği düşünün:

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

İleri beyan ederek User , MyMessageBoxyine de bir işaretçi veya ona referans oluşturabilir:

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

Sen yapamazsın etrafında bu başka bir yol yapın: belirtildiği gibi, bir sınıf üyesi bir tanım olması gerekir. (Bunun nedeni, derleyicinin ne kadar bellek kapladığını Userbilmesi ve üyelerinin boyutunu bilmesi gerektiğini bilmesi gerektiğidir.)

class MyMessageBox;

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

Henüz boyutunu bilmediği için işe yaramaz.


Bir yan not olarak, bu işlev:

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

Muhtemelen bunların ikisini de işaretçi ile almamalı. Mesaj olmadan mesaj gönderemezsiniz veya kullanıcı göndermeden mesaj gönderemezsiniz. Ve bu iki durum da, her iki parametreye de argüman olarak null iletilerek ifade edilebilir (null, tamamen geçerli bir işaretçi değeridir!)

Bunun yerine, bir referans kullanın (muhtemelen sabit):

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

3
+1 Bugün bir şey öğrendim - İleriye dönük beyan etmenin MyMessageBoxyeterli olacağını düşündüm . Ya MyMessageBoxdeğişken tipte Userolsaydı - bu bir kilitlenme olur muydu?
Amarghosh

14
@Amargosh: Evet, imkansız olurdu. Çünkü sıra Mantıken imkânsız Userbir olurdu MessageBoxbir olurdu ki User, hangi bir olurdu MessageBoxbir olurdu ki User, hangi bir olurdu MessageBoxbir olurdu ki User, bir olurdu hangi MessageBoxbir olurdu ki User...
GManNickG


3

C ++ derleyicileri, girdilerini bir kez işler. Kullandığınız her sınıf önce tanımlanmış olmalıdır. Tanımlamadan MyMessageBoxönce kullanırsınız . Bu durumda, iki sınıf tanımını kolayca değiştirebilirsiniz.


Olarak çalışmaz takas MyMessageBoxvardır User's yöntem Bildirimde türü.
Amarghosh

Aslında bu tanım, sınıfı kullanmazUser . Önemli ayrım, çünkü bu, Kullanıcı sınıfının tanımlanmadan , yalnızca o noktada bildirilmesi gerektiği anlamına gelir . Ancak GMan'ın kapsamlı gönderisine bakın.
MSalters

Evet, ancak tanımların değiştirilmesi Userhenüz tür bildirilmediğinden işe yaramayacaktır .
Amarghosh

3

Kullanıcıdan önce MyMessageBox'ı tanımlamanız gerekir - çünkü Kullanıcı, MyMessageBox nesnesini değere göre dahil eder (ve bu nedenle derleyici boyutunu bilmelidir).

Ayrıca, MyMessageBox için Kullanıcı beyanını iletmeniz gerekir - çünkü MyMessageBox, Kullanıcı * türünün üyesini içerir.


3

İlgili bir notta, eğer varsa:

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

Daha sonra bu da işe yarar, çünkü Kullanıcı MyMessageBox'ta bir işaretçi olarak tanımlanır.


1
İleri beyan terimdir
benziv

1

Prototipi kullanmadan önce beyan etmelisiniz:

class User;

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

class User
{
public:
 MyMessageBox dataMsgBox;
};

düzenleme : Türleri değiştirdi


1
Hayır, çalışmayacak. Sınıf üyeleri tanımlanmalı, forqward bildirilmemelidir.
MSalters

1

C ++ 'da her bir başlık dosyası için bir sınıfa sahip olmanız tavsiye edilir, SO [ 1 ]' deki bu tartışmaya bakın . GManNickG cevabı bunun neden olduğunu anlatır. Ancak bunu çözmenin en iyi yolu, Usersınıfı bir başlık dosyasına ( User.h) ve MyMessageBoxsınıfı başka bir başlık dosyasına ( MyMessageBox.h) koymaktır . Sonra da User.hsiz dahil edersiniz MyMessageBox.hve MyMessageBox.hsiz de dahil edersiniz User.h. "Gaurd'ları dahil et" [Kodunuzun başarıyla 2 ] 'i .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.