2013-02-05 17 views
3

我試圖建立一個基本的實體/對象管理系統,我有兩個類,一個用於繼承實體的基類,另一個用於管理和控制它們。如何定義循環依賴關係的C++類?

這是我想要使用的源代碼:

#include <iostream> 
#define MAX_ENTS 400 
class EFentity; 
class EFiterator; 
class EFentity { 
    public: 
      EFentity(); 
      virtual bool step(); 
      virtual void create(EFiterator*,int); 
      virtual void destroy(); 
    private: 
      int holder_id; 
      EFiterator* holder; 
}; 
EFentity::EFentity(void) { 
    // add base entity stuff 
} 
void EFentity::destroy() { 
    holder->ents[holder_id]=NULL; 
    std::cout << "destroying object id "<<holder_id; 
    delete this; 
} 
void EFentity::create(EFiterator* h,int pos) { 
    holder=h; 
    holder_id=pos; 
} 
bool EFentity::step() { 
    return false; 
} 
class EFiterator { 
public: 
    EFentity* ents[MAX_ENTS]; 
    int e_size; 
    EFiterator(); 
    void push(EFentity* e); 
    void update(); 
}; 
EFiterator::EFiterator() { 
    e_size=0; 
} 
void EFiterator::update() { 
    for(int i=0;i<e_size;i++) { 
      if (!ents[i]->step()) { 
       std::cout << "entity id "<< i<<" generated a fault!\n"; 
      } else std::cout << "entity id "<<i<<" passed step test.\n"; 
    } 
} 
void EFiterator::push(EFentity* e) { 
    ents[e_size]=e; 
    e->create(this,e_size++); 
} 
int main() { 
    EFiterator main_iterator; 
    main_iterator.push(new EFentity()); 
    main_iterator.update(); 
    std::cin.get(); 
    return 0; 
} 

此代碼顯然不編譯,這裏是錯誤:

In member function `virtual void EFentity::destroy()': 

[20] invalid use of undefined type `struct EFiterator' 
[5] forward declaration of `struct EFiterator' 

我所看到的問題就像之前的SO一樣,但它們不需要訪問其他類的成員變量和函數,所以可以用指針輕鬆解決。

認爲這可以通過具有原型函數來訪問的EFiterator內的陣列來解決,但有沒有辦法用一些棘手的類操作順利做到這一點?

回答

3

EFentity::destroy()需要知道具體類型的EFiterator當它調用

holder->ents[holder_id]=NULL; 

EFentity::destroy()EFiterator定義應該解決的問題,例如,把它放在後EFiterator

void EFiterator::push(EFentity* e) { 
    ents[e_size]=e; 
    e->create(this,e_size++); 
} 

void EFentity::destroy() { 
    holder->ents[holder_id]=NULL; 
    std::cout << "destroying object id "<<holder_id; 
    delete this; 
} 

通常在向前聲明類型頭文件並在.cpp文件中包含具體類型,該文件打破circular include問題。

EFentity.h

class EFiterator; 
class EFentity { 
    public: 
      EFentity(); 
      virtual bool step(); 
      virtual void create(EFiterator*,int); 
      virtual void destroy(); 
    private: 
      int holder_id; 
      EFiterator* holder; 
}; 

EFentity.cpp

#include "EFiterator.h" 

EFentity::EFentity(void) { 
    // add base entity stuff 
} 
void EFentity::destroy() { 
    holder->ents[holder_id]=NULL; 
    std::cout << "destroying object id "<<holder_id; 
    delete this; 
} 
void EFentity::create(EFiterator* h,int pos) { 
    holder=h; 
    holder_id=pos; 
} 
bool EFentity::step() { 
    return false; 
} 
+0

哇,謝謝。我很高興看到這些簡單的答案。很好的例子。 – object

1

的問題是,你向前聲明類型EFIterator,然後試圖定義之前訪問它的成員是可見的編譯器。當編譯器讀取EFentity::destroy()的定義時,它需要知道EFIterator有一個名爲ents的成員。

的解決方案很容易達到:把兩個聲明提前定義的,就像這樣:

#include <iostream> 
#define MAX_ENTS 400 
class EFentity; 
// Now we can refer to EFentity by pointer or reference. 

class EFiterator { 
public: 
    EFentity* ents[MAX_ENTS]; 
    int e_size; 
    EFiterator(); 
    void push(EFentity* e); 
    void update(); 
}; 
// Now we can refer to EFiterator by pointer, reference, or value. 

class EFentity { 
public: 
    EFentity(); 
    virtual bool step(); 
    virtual void create(EFiterator*,int); 
    virtual void destroy(); 
private: 
    int holder_id; 
    EFiterator* holder; 
}; 
// Now we can refer to EFentity by pointer, reference, or value. 

EFiterator::EFiterator() { 
    // ... 

現在對於EFiterator聲明可以引用類型EFentity爲指針(不需要知道什麼除此之外,它是一個UDT),並且EFentity的聲明可以指EFiterator類型作爲指針(除了EFiterator是UDT之外,不需要知道任何其他信息)。 EFiteratorEFentity聲明的順序無關緊要;你可以很容易地反轉他們是這樣的:

#include <iostream> 
#define MAX_ENTS 400 
class EFiterator; 
// Now we can refer to EFiterator by pointer or reference. 

class EFentity { 
public: 
    EFentity(); 
    virtual bool step(); 
    virtual void create(EFiterator*, int); 
    virtual void destroy(); 
private: 
    int holder_id; 
    EFiterator* holder; 
}; 
// Now we can refer to EFentity by pointer, reference, or value. 

class EFiterator { 
public: 
    EFentity* ents[MAX_ENTS]; 
    int e_size; 
    EFiterator(); 
    void push(EFentity*); 
    void update(); 
}; 
// Now we can refer to EFiterator by pointer, reference, or value. 

EFiterator::EFiterator() { 
    // ... 

直到你到達定義你需要有前面聲明可用。

+0

謝謝,因爲它表達了與以前的答案相同的點。 – object