2009-12-04 208 views
4

我正在開發一個基於用戶控制在屏幕上的區域之間移動的球的遊戲。對於屏幕上的「地圖」在文件ThreeDCubeGame.cpp定義:非法調用非靜態成員函數(C++)?

char m_acMapData[MAP_WIDTH][MAP_HEIGHT]; 

的ThreeDCubeGame.cpp處理大部分的東西與地圖做的,但球員(和鍵盤輸入)由ThreeDCubePlayer控制的.cpp。當玩家進入新的地圖單元格時,遊戲必須檢查該單元格的內容並採取相應的行動。此功能在ThreeDCubeGame.cpp是什麼,我想使用:

inline char GetMapEntry(int iMapX, int iMapY) { return m_acMapData[iMapX][iMapY]; } 

因此,以檢查球員是否准予遷入我用這個函數調用從ThreeDCubePlayer.cpp映射單元:

if (ThreeDCubeGame::GetMapEntry(m_iMapX+MAP_OFF_X, m_iMapY+MAP_OFF_Y) == ' ') 
{ 
// do stuff 
} 

但是,當我編譯這個,我得到警告「錯誤C2352:'ThreeDCubeGame :: GetMapEntry':非法調用非靜態成員函數」。這與變量的範圍有關嗎?它是否可修復而不重新設計所有代碼?

回答

4

GetMapEntry不是static因此,如果沒有ThreeDCubeGame類型的對象,就不能調用它。

替代方案:
- 製作GetMapEntry靜:static inline char GetMapEntry
- 創建ThreeDCubeGame的實例,並做instance.GetMapEntry(

+0

感謝您的回答。 在我的程序中ThreeDCubePlayer是ThreeDCubeGame中的一個實例 - 這是否意味着我可以在ThreeDCubePlayer中創建一個ThreeDCubeGame的實例來引用相同的二維數組? – benwad 2009-12-04 14:06:34

+0

你可以使用ThreeDCubePlayer.GetMapEntry(或this-> GetMapEntry(從內部。 – 2009-12-04 14:08:15

0

您試圖調用類方法。那是你的意圖嗎?或者你的意思是GetMapEntry是一個實例方法?如果它是一個類方法,它需要被標記爲靜態。如果它是實例方法,則需要使用ThreeDCubeGame的實例調用它。另外,即使是一個班級的成員,也是GetMapEntry

0

錯誤表明您正在調用GetMapEntry函數作爲靜態函數,而您已聲明它爲成員函數。您需要:通過ThreeDCubeGame實例

  • 調用它:threedcubegameinstance.GetMapEntry()
  • 聲明GetMapEntry功能爲靜態(內聯之前添加靜態,使m_acMapData靜太)。
1

ThreeDCubeGame是一類,而不是一個實例,因此,你只能用它來訪問靜態成員(即用關鍵字static成員函數) 你必須實例化這個類的一個對象來使用非靜態成員

ThreeDCubeGame map; 
... 
map.GetMapEntry(iMapX, iMapY). 
9
class A { 
    int i; 
public: 
    A(): i(0) {} 
    int get() const { return i; } 
}; 

int main() { 
    A a; 
    a.get(); // works 
    A::get(); // error C2352 
} 

有沒有對象調用與功能。

0

您錯過了「靜態」關鍵字。

// .h 
class Playfield 
{ 
public: 
    static char GetTile(int x, int y); 
    // static on a method means no 'this' is involved 
}; 

// .cpp 
static char tiles[10][10] = {}; 
// static on vars in .cpp prevents access from outside this .cpp 

char Playfield::GetTile(int x, int y) 
{ 
    // handle invalid args 

    // return tile 
    return tiles[x][y]; 
} 

還有其他的選擇,如果你只需要一個獨特的球場: 可以使球場單身,把它變成一個命名空間或使用全局函數。 從調用者的角度來看,結果是一樣的。

附註: 由於所有這些使用靜態和/或全局變量,它本質上不是線程安全的。

如果您需要多個遊戲區域和/或想要使用多線程安全地玩遊戲和/或想要以OOP方式完全執行此操作,您需要一個Playfield實例來調用該函數('this'指針):

class Playfield 
{ 
public: 
    char GetTile(int x, int y) const { return this->tiles[x][y]; } 
    // you can omit 'this->', but it's inherently present because 
    // the method is not marked as static 
public: 
    Playfield() 
    { /*you will have to initialize 'this->tiles' here because 
     you cannot use the struct initializer '= {}' on member vars*/ } 

private: 
    char tiles[10][10]; 
}; 

調用代碼將使用操場這樣的:

void main() 
{ 
    // static version 
    char tile11 = Playfield::GetTile(1, 1); 

    // non-static version 
    Playfield myPlayfield; 
    char tile12 = myPlayfield.GetTile(1, 2); 
} 
0

它可以是有用的包含的功能的集合類,沒有任何數據成員,如果你不想要公開幫手功能。
否則這將是更實際的使用命名空間中收集這些功能
例:

class Solvers 
{ 
public: 
    void solve_a(std::vector<int> data); 
    void solve_b(std::vector<int> data, int value); 
private: 
    int helper_a(int a, int b); 
} 

但一類在使用前需要進行初始化。
使這些功能可用將它們標記在類的靜態最簡單的方法:
static void solve_a(std::vector<int> data);
然後,成員函數可以用作:
Solver::solve_a(my_vector);

另一種方式是,以初始化類使用前:
Solver solver;
solver.solve_a(my_vector);

而第三種方法,而不是之前所提到的,默認情況下初始化它杜爾ing使用:
Solver().solve_a(my_vector);

相關問題