2012-11-02 198 views
9

我正在通過做一個小型機器人模擬來學習C++,而且我在類內靜態成員函數時遇到了問題。C++靜態成員函數和變量

我已經定義是這樣我的環境類:

class Environment { 
    private: 
     int numOfRobots; 
     int numOfObstacles; 

     static void display(); // Displays all initialized objects on the screen 

    public: 
     Robot *robots; 
     Obstacle *obstacles; 

     // constructor 
     Environment(); 

     static void processKeySpecialUp(int, int, int); // Processes the keyboard events 
}; 

然後在構造函數中我初始化機器人和障礙是這樣的:

numOfRobots = 1; // How many robots to draw 
numOfObstacles = 1; 
robots = new Robot[numOfRobots]; 
obstacles = new Obstacle[numOfObstacles]; 

這裏是例如靜態函數的使用這些變量:

void Environment::display(void) { 
    // Draw all robots 
    for (int i=0; i<numOfRobots; i++) { 
     robots[i].draw(); 
    } 
} 

當我嘗試編譯時,收到錯誤消息如

error: invalid use of member ‘Environment::robots’ in static member function 

我試圖使numOfRobots,numOfObstacles,機器人和障礙靜態,但後來我得到了這樣的錯誤

error: undefined reference to 'Environment::numOfRobots' 

我將不勝感激有人可以解釋我什麼我做錯了。 謝謝!

+0

在你的代碼的靜態版本中,你沒有定義'Environment :: numOfRobots',你只聲明瞭它。將'int Environment :: numOfRobots = 1;'添加到其中一個源文件中。一本關於C++的書將解釋如何聲明和定義變量以及其他重要信息。 – john

+1

既然你說你正在學習C++,我可以建議使用標準庫嗎?特別是'std :: vector'而不是原始數組。 – bitmask

回答

12

靜態方法不能使用其類中的非靜態變量。

這是因爲一個靜態方法可以調用像Environment::display()沒有類實例,這使得它內部使用的任何非靜態變量是不規則的,也就是說,它們沒有父對象。

你應該考慮爲什麼你試圖使用靜態成員來達到這個目的。基本上,怎麼可以用一個靜態方法一個例子是這樣的:

class Environment 
{ 
private: 
    static int maxRobots; 
public: 
    static void setMaxRobots(int max) 
    { 
     maxRobots = max; 
    } 
    void printMaxRobots(); 
}; 

void Environment::printMaxRobots() 
{ 
    std::cout << maxRobots; 
} 

而你也必須在全局範圍內初始化的變量,如:

int Environment::maxRobots = 0; 

然後,裏面main爲例如,您可以使用:

Environment::setMaxRobots(5); 

Environment *env = new Environment; 
env->printMaxRobots(); 
delete env; 
+0

你有一個想法,這是如何解決?我試圖讓這些變量爲靜態的,但我得到的錯誤(請參閱我的問題的第二部分)... –

+1

您必須初始化靜態變量,請參閱[靜態成員函數](http://publib.boulder。 ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr039.htm)。 –

1

靜態成員函數是一種可以在沒有這種實際對象的情況下調用的函數。但是,函數Environment::display使用變量numOfRobotsrobots,它們都生活在Environment類的特定實例中。要麼使display非靜態(爲什麼你想要它是靜態的?)或使機器人也是Environment的靜態成員。

在你的情況下,我沒有看到製作displayprocessKeySpecialUpstatic的原因,所以只要讓它們成爲普通的成員函數即可。如果您想知道什麼時候成員函數應該是static,請考慮如果沒有創建該類的對象(即沒有調用構造函數),該函數是否有意義。如果該功能在這種情況下沒有意義,那麼它不應該是static

+0

我正在使用Glut庫來處理圖形,我需要保持靜態顯示。正如我之前所說,我試圖讓這些變量是靜態的,但我得到錯誤:未定義的引用'Environment :: numOfRobots' –

0

靜態方法無法訪問實例變量。如果你想從方法中訪問實例變量remove static。如果這些值可以通過所有機器人實例是相同的,那麼使它們成爲靜態變量並且該方法可以保持靜態。

2

static成員是那些使用它們不需要實例化,所以他們沒有this,因爲this需要實例:

class foo { 
public 
    void test() { 
     n = 10; // this is actually this->n = 10 
    } 
    static void static_test() { 
     n = 10; // error, since we don't have a this in static function 
    } 
private: 
    int n; 
}; 

正如你看到的,你不能調用一個實例函數或使用實例成員在static函數內。所以一個函數應該是靜態的,如果它的操作不依賴於實例,並且如果你需要在你的函數中需要一個動作,需要this,你必須想到爲什麼我把它稱爲static,而它需要this

成員變量是static是否應該在class的所有實例之間共享的,它不屬於任何特定的class實例,例如我可能希望我的類創建實例的計數器:

// with_counter.h 
class with_counter { 
private: 
    static int counter; // This is just declaration of my variable 
public: 
    with_counter() {++counter;} 
    ~with_counter() {--counter;} 

    static int alive_instances() { 
     // this action require no instance, so it can be static 
     return counter; 
    } 
}; 

// with_counter.cpp 
int with_counter::counter = 0; // instantiate static member and initialize it here 
3

這裏有兩個問題 - 你試圖實現的算法和它爲什麼不編譯的機制。

爲什麼不編譯。

你在混合靜態和實例變量/方法 - 這很好。但是你不能從一個靜態方法中引用一個實例變量。這是「無效使用」錯誤。如果你仔細想想,這是有道理的。只有一個「static void display()」方法。所以如果它試圖引用非靜態(實例)變量「機器人」,它指的是哪一個?可能有10 ...或沒有。

您嘗試實施的邏輯。

它看起來像你想要一個管理N個機器人的單個Environment類。這完全合乎邏輯。一種常見的做法是將Environment設置爲「單例」 - 一個只允許單個實例的實例變量。然後它可以根據需要分配儘可能多的機器人,並自由地提及它們,因爲沒有靜態變量/方法。

另一種方法是繼續並使整個Environment類爲靜態。然後保留一個(靜態)機器人列表。但我認爲現在大多數人會說選項#1是要走的路。

+0

謝謝!我怎樣才能讓環境變成一個單身人士?從來沒有聽說過... –

+0

@ user1739770這個簡單的答案是你有一個靜態方法,返回一個指向你的類的指針;如果沒有,則創建並返回它,否則返回指向現有指針的指針。這樣你有一個'實例'類,但從來沒有得到它的一個以上的副本。實際上,它有點粘:雖然看到http://stackoverflow.com/questions/1008019/c-singleton-design-pattern。 –

2

第一個錯誤提示您不能在靜態成員函數中使用非靜態成員。

第二個說,你需要定義除靜態成員聲明他們必須定義靜態成員變量外的一類,在源文件(未在頭)是這樣的:

int Environment::numOfRobots = 0; 

你不需要任何靜態成員。要有一個絕對正確和便攜的GLUT界面,請使用Environment類型的文件級對象和用C連接聲明的文件級(非成員)函數。爲方便起見,還有一個名爲display的成員函數。

class Environment 
{ 
public: 
    void display() { ... } 
    ... 
}; 

static Environment env; 
extern "C" void display() { env.display(); }