2015-11-05 35 views
3

具有國家或大陸的Map.h下面的代碼不被認定這個問題提交不明身份標識C++,但它的標識

Map.h:

#ifndef MAP_H 
#define MAP_H 
#include<string> 
#include<vector> 
#include<iostream> 
#include<fstream> 
//#include "Country.h" 

using namespace std; 
class Map{ 

private: 
    vector<Country> countries; 
    vector<Continent> continents; 
    vector<vector<int> > adjacents; 
    string author; 
    string image; 
    string wrap; 
    string scroll; 
    string warn; 
public: 
    Map(ifstream); 
    Map(); 
    void save(); 
    void setAdjacent(Country&, Country&); 
    void placeWithin(Continent&, Country&); 
    int numOfCountries(); 
    int numOfContinents(); 
    bool verify(); 
    bool isAdjacent(Country*, Country&); 
    bool hasAdjacent(Country*); 
    bool hasCountry(Continent&); 

}; 
#endif 

無論添加的評論包括,我仍然得到錯誤。

下面是其他兩個文件

Continent.h:

#ifndef CONTINENT_H 
#define CONTINENT_H 

#include "Map.h" 
using namespace std; 
class Continent 
{ 
private: 
    string name; 
    int bonus; 
    vector<Country> countries; 
public: 
    void addCountry(Country&); 
    int getOwner(); 
    int getBonus(); 
    int getSize(); 
    string getName(); 
    bool hasCountry(Country&); 


}; 
#endif 

Country.h:

#ifndef COUNTRY_H 
#define COUNTRY_H 
#include "Continent.h" 


using namespace std; 

class Country{ 
    private: 
     static int nextCountryNumber; 
     int countryNumber; 
     Map map; 
     string name; 
     int x, y; 
     Continent continent; 
     vector<Country> adjacents; 
    public: 
     Country(string, int, int, Continent&, Map&); 
     string getName(); 
     int getX(); 
     int getY(); 
     Continent getContinent(); 
     bool isAdjacentTo(Country&); 
     bool hasAdjacent(); 
     void addAdjacent(Country&); 
     string toString(); 
}; 
#endif 

我認爲它的某種循環引用的,但我不能找到此是這樣的...

+0

爲什麼要在Continent.h中包含Map.h? –

+0

@XiaotianPei,因爲'Country'中使用'Map','Country.h'包含'Continent.h',其中包含'Map.h' – GreatAndPowerfulOz

+0

通常在頭文件中使用forward聲明而不是'include'。否則,您可能會遇到循環依賴關係。另外,具體是什麼錯誤?你能把它粘貼在這裏嗎? – personjerry

回答

0

對於初學者,在Map.h你需要噸鄰class Map聲明之前向前聲明類CountryContinent

class Country; 
class Continent; 

3

通常在.h文件中,您不希望包含其他頭文件。他們只是聲明,所以他們不需要知道其他類是什麼樣的。刪除#include "blah.h",而是在需要它們的地方寫下轉發聲明class blah;。這是,除非你直接在你的類中存儲一個對象blah,在這種情況下,你需要包含blah.h,因爲編譯器需要知道該對象有多大。你可以避免這些包括,而不是直接存儲指向對象而不是對象(事實上,這是更常見的做法,因爲當你複製構造時不需要複製所有數據)。

編輯:作爲一個附註,你通常只想包括必要的#includes(即iostream),也不要在你的頭文件中使用using namespace std;,因爲包含頭文件的另一個文件可能不想使用std命名空間。相反,在你的實現文件中做這些事情。我已經在下面做了相應的更改。編輯2:另外,請記住,map是std中的一種數據結構類型,所以在您命名事物map(我建議使用不同的名稱)時要小心。

編輯3:正如在註釋中指出的那樣,std容器需要完整聲明它們包含的對象,所以無論何時您有vector<blah>,您都必須包含blah.h。還要考慮到這一點:在其自己的聲明中包含一個對象blah是有問題的。由於對象包含自己的一個實例,這是遞歸的,所以應該分配多少空間?你可以通過pointer-to-blahblah(一個指針只是一個固定的大小)來解決這個問題。出於類似的原因,Country類包含vector<Country>是有問題的。這可以通過將vector<Country>更改爲vector<Country*>來解決。因此,爲了使這些技術上可以通過C++標準進行編譯,並針對包含其他頭文件來清理設計,我已經將引用Country,Continent和的成員變量更改爲它們各自的指針,您需要進行鏡像的更改在實現文件中。我也修改Map(std::ifstream);Map(std::ifstream &);,如另一條評論所建議的,因爲我嚴重懷疑你打算在這裏複製ifstream。

代碼:

Map.h:

#ifndef MAP_H 
#define MAP_H 
#include<string> 
#include<vector> 
#include<fstream> 

class Country; 
class Continent; 

class Map{ 

private: 
    std::vector<Country*> countries; // consider pointers instead 
    std::vector<Continent*> continents; // consider pointers instead 
    std::vector<std::vector<int> > adjacents; // (just ints, so no pointers needed) 
    std::string author; 
    std::string image; 
    std::string wrap; 
    std::string scroll; 
    std::string warn; 
public: 
    Map(std::ifstream &); 
    Map(); 
    void save(); 
    void setAdjacent(Country&, Country&); 
    void placeWithin(Continent&, Country&); 
    int numOfCountries(); 
    int numOfContinents(); 
    bool verify(); 
    bool isAdjacent(Country*, Country&); 
    bool hasAdjacent(Country*); 
    bool hasCountry(Continent&); 

}; 
#endif 

Continent.h:

#ifndef CONTINENT_H 
#define CONTINENT_H 
#include<string> 
#include<vector> 

class Country; 

class Continent 
{ 
private: 
    std::string name; 
    int bonus; 
    std::vector<Country*> countries; 
public: 
    void addCountry(Country&); 
    int getOwner(); 
    int getBonus(); 
    int getSize(); 
    std::string getName(); 
    bool hasCountry(Country&); 


}; 
#endif 

Country.h:

#ifndef COUNTRY_H 
#define COUNTRY_H 
#include<string> 
#include<vector> 

class Map; 
class Continent; 

class Country{ 
    private: 
     static int nextCountryNumber; 
     int countryNumber; 
     Map *map; 
     std::string name; 
     int x, y; 
     Continent *continent; 
     std::vector<Country*> adjacents; 
    public: 
     Country(std::string, int, int, Continent&, Map&); 
     std::string getName(); 
     int getX(); 
     int getY(); 
     Continent getContinent(); 
     bool isAdjacentTo(Country&); 
     bool hasAdjacent(); 
     void addAdjacent(Country&); 
     std::string toString(); 
}; 
#endif 
+1

爲了使這是一個很好的答案,你需要刪除'using namespace std;'語句。這是一般的糟糕形式,而且在頭文件中形式極其糟糕。 –

+0

哈哈,我只是做了那些修改。我們在想同樣的事情。 – personjerry

+0

您需要進行三項更改:(1)Continent.h不需要轉發聲明'Map'。 (2)Continent.h需要轉發聲明'Country'。 (3)Country.h需要'#include' Map.h和Continent.h查看數據結構。 「Continent」類根本沒有引用「Map」,但它引用了「Country」。 'Country'類具有'Map'和'Continent'類型的數據成員,因此前向聲明是不夠的。 –

1

我認爲它的某種cir cular的參考,但我無法找到那裏的情況...

你有比循環參考問題更糟糕。你有一個糾結的混亂。你可以通過@ personjerry的回答來解決循環引用問題。這無助於解決您糾結的混亂問題。

後一個問題:您的類Country具有類型MapContinent的數據成員以及相鄰的Country對象的向量。您的班級Continent在該大陸有一個向量Country對象。您的類Map具有CountryContinent對象的向量。 Country的名字FooMap對象的countries數據成員與CountryCountry的名稱不同在Continent對象的countries數據成員中。更糟的是,你所有的獲得者都會返回副本。副本上有副本副本。這是一團糟。

解決此問題的pre-C++ 11方法是使用指針並仔細考慮誰擁有什麼。在你的情況下,類Map似乎是主要的,因爲這是從輸入流構造的類。類別Country中對ContinentMap的引用應該是指針或引用。 CountryContinent類中的Country對象的向量應該是指針的向量。

更現代的方法是使用智能指針(在你的情況下共享指針)。人們仍然需要考慮一下誰擁有什麼,在這裏就是這種情況。循環引用在共享指針方面存在一些問題。這個結構對循環引用有很大的潛力。


旁白:使用using namespace std;被廣泛認爲是不好的形式。當構造文件在頭文件中時,幾乎被普遍認爲是非常糟糕的形式。

0

您的代碼設計中存在一些問題。有遞歸容器定義。

要注意的第一個要點是std::vector必須具有完整的類型作爲模板參數。這意味着你不能擁有一個包含自身向量的類;所以你將不得不重新考慮設計:

class Country 
{ 
    // ... 
    vector<Country> adjacents; 

類似的說明適用於您的其他載體:這是不夠的前瞻性聲明一個類,然後宣佈它的載體;除非class Country已完全定義,否則class Map內部不能有vector<Country>。它不可能,因爲class Country也包含Map


然而,看着你的等級和載體設計的其餘部分,它看起來更像是一個什麼Java或C#編碼器會做,其中容器包含對象的引用,而不是對象。

特別地,包含MapCountry沒有多大意義。一個典型的設計只會有一個地圖,而地圖包含很多國家。但在您的設計中,每個國家都有自己的地圖,與任何其他國家的地圖完全分開(並且完全與任何全球地圖分開)。

爲了在C++中分享許多用戶中單個實例的引用,正確的方法是使用shared_ptr作爲被引用對象的容器。 (這也限制了你如何分配對象 - 你必須用make_shared而不是直接聲明對象來創建它們)。

我猜你可能想要對國家和地圖做同樣的事情。你寧願有一個國家對象爲每個國家,並從其鄰國各國引用該國家等

國家需要持有國家名單的替代解決方案將要麼持有國家/地區名單/在需要時查找的名稱;或使用允許不完整類型的聲明的非標準容器。 Boost容器庫有一些這些。