5

我有一個帶有實例函數(或方法?)的類。從一個實例中,我嘗試將指向這些函數的指針傳遞給一個庫。該庫期望靜態功能。將指針傳遞給成員函數

當我將指針傳遞給回調函數時,編譯器會抱怨我的函數不是靜態的。我試圖讓它們變成靜態的,但如果我這樣做了,那麼我無法從函數內部訪問實例字段。

我怎麼能解決這個問題?

類似的問題是:Using a C++ class member function as a C callback function他們建議靜態的方法。但是我做不到,或者我看不到我能做到。

代碼

GlutController::GlutController (int argc, char **argv) { 

    // stuff .. 

    // Register callbacks 
    glutSpecialFunc(OnSpecialKeys); // Error, need static functions 
    glutReshapeFunc(OnChangeSize); // Error... 
    glutDisplayFunc(OnRenderScene); // Error... 

    // stuff .. 
} 

GlutController::~GlutController() { 

} 

void GlutController::OnChangeSize(int aNewWidth, int aNewHeight){ 

    glViewport(0,0,aNewWidth, aNewHeight); 
    mViewFrustrum.SetPerspective(APP_CAMERA_FOV,    // If this function is 
      float(aNewWidth)/float(aNewHeight),  // static, this won't 
      APP_CAMERA_NEAR,         // work 
      APP_CAMERA_FAR); 
    mProjectionMatrixStack.LoadMatrix(      // Same here 
      mViewFrustrum.GetProjectionMatrix()); 
    mTransformPipeline.SetMatrixStacks(mModelViewMatrixStack, // Same here 
      mProjectionMatrixStack); 

} 

void GlutController::OnRenderScene(void){ 
    mGeometryContainer.draw();        // Won't work if static 
} 

void GlutController::OnSpecialKeys(int key, int x, int y){ 
    mGeometryContainer.updateKeys(key);      // Won't work if static 
} 

聲明:我剛剛開始C++。我閱讀了所有加速C++,這是我第一個嘗試使用該語言的項目。我的背景是Java。

回答

7

你試圖做的是不可能的。實際上這是glut的錯。

事情是這樣的:

  • glut要調用一個函數,沒有給它的數據,
  • 您希望您的功能使用一些數據,

這是相互矛盾的需求。我相信glut決定你可以安全地使用全局變量。

所以,一種解決方案是使用靜態函數,與靜態數據。或者更好的解決方案是切換到SDL

+0

我對glut的瞭解不多,但它聽起來像是需要一些可調用的東西,它不包含任何參數(包含隱含的參數)。所以不會有一個適當構建的'std :: function'能做到這一點嗎? – juanchopanza 2012-08-03 09:31:44

+2

任何開發不透明的庫函數,不能接受用戶定義的參數(例如用於回調)的人都應該被解僱,晉升爲營銷/銷售,或者獲得經濟刺激去爲競爭對手公司工作。 – 2012-08-03 09:58:57

+0

@Shahbaz我正在嘗試做一個簡單的演示,並且我認爲在模板代碼方面,與SDL相比,過度使用非常簡單。另外,我正在使用「OpenGL SuperBible」這本書來指導我。 我認爲使用static/global將是不可避免的,或者像Nick在他的回答中所說的那樣使用Singleton。 – AntoineG 2012-08-03 12:15:21

1

你應該有一個static methodinstance(可能靜態)調用instance成員函數從static功能

事情是這樣的:

//static method 
void MyClass::myCallback() 
{ 
    static MyClass instance; //or you can store your in instance in some Singleton, or 
    //possibly create a temporary 
    instance.nonStaticMethod(); 
} 
3

總之,你不能。 C++成員函數實際上是「鏈接」到對象的實例。在較低級別上,它們有一個額外的參數,它實際上是指向此對象實例的指針。

所以,你必須使用靜態函數,並且,由於glut不會讓你傳遞一個參數來識別當前實例,所以你必須提出一些解決方法。最簡單的解決方法是使用靜態成員。如果你的GlutController是單身人士(我認爲是),你會沒事的。

2

使用指向你的GlutInstance(靜態函數+靜態數據,如另一個答案中提到的)的文件作用域靜態變量是可能的,而且顯然是安全的。

static GlutController* s_this; 

static void s_OnChangeSize(int w, int h) { s_this->OnChangeSize(w, h); } 

GlutController::GlutController (int argc, char **argv) { 
    s_this = this; 

    glutSpecialFunc(s_OnSpecialKeys); 
} 

GlutController::~GlutController() { s_this= 0; } 

void GlutController::OnChangeSize(int w, int h) { /* non-static stuff */ } 

s_this僅在本地文件,例如可見任何從另一個文件調用GlutController構造函數的代碼都不可見。