2008-09-24 16 views
26

Bir sınıf içinde üye işlevini, üye işlev sınıfı işaretçisi alan bir işleve geçirmeye çalışıyorum. Sorun şu ki, bu işaretçiyi kullanarak bunu sınıfta nasıl düzgün yapılacağından emin değilim. Önerisi olan var mı?Bir üye fonksiyon işaretçisini nasıl geçirirsiniz?

class testMenu : public MenuScreen{ 
public: 

bool draw; 

MenuButton<testMenu> x; 

testMenu():MenuScreen("testMenu"){ 
    x.SetButton(100,100,TEXT("buttonNormal.png"),TEXT("buttonHover.png"),TEXT("buttonPressed.png"),100,40,&this->test2); 

    draw = false; 
} 

void test2(){ 
    draw = true; 
} 
}; 

fonksiyon x.SetButton (...) "nesne" bir şablon başka bir sınıfta, bulunan: Burada

üye işlevini geçiyor sınıfın bir kopyasıdır.

void SetButton(int xPos, int yPos, LPCWSTR normalFilePath, LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, int Width, int Height, void (object::*ButtonFunc)()) { 

    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height); 

    this->ButtonFunc = &ButtonFunc; 
} 

Daha sonra kullanabilmem için bu işlevi nasıl düzgün şekilde gönderebileceğime dair herhangi bir tavsiyede bulunursa.

cevap

32

İşaretçi ile üye işlevini çağırmak için iki şeye ihtiyacınız vardır: Nesneye bir işaretçi ve işleve bir işaretçi. Sen Sonra her iki işaretçiler kullanarak işlevini çağırabilirsiniz MenuButton::SetButton()

template <class object> 
void MenuButton::SetButton(int xPos, int yPos, LPCWSTR normalFilePath, 
     LPCWSTR hoverFilePath, LPCWSTR pressedFilePath, 
     int Width, int Height, object *ButtonObj, void (object::*ButtonFunc)()) 
{ 
    BUTTON::SetButton(xPos, yPos, normalFilePath, hoverFilePath, pressedFilePath, Width, Height); 

    this->ButtonObj = ButtonObj; 
    this->ButtonFunc = ButtonFunc; 
} 

hem gerekir:

((ButtonObj)->*(ButtonFunc))(); 

MenuButton::SetButton() için nesneye işaretçi geçmek unutmayın:

testMenu::testMenu() 
    :MenuScreen("testMenu") 
{ 
    x.SetButton(100,100,TEXT("buttonNormal.png"), TEXT("buttonHover.png"), 
     TEXT("buttonPressed.png"), 100, 40, this, test2); 
    draw = false; 
} 
+2

'Sınıfa bir işaretçi - 'Nesne bir işaretçi' olmalıdır? – Vorac

+0

Çok teşekkürler. Sözdiziminin ((ButtonObj) -> * (ButtonFunc))() – nathanesau

2

gör C++ derleyicileri), __closure anahtar sözcüğünü kullanabilirsiniz. Bir small article about C++Builder closures buldum. Bunlar öncelikle Borland VCL ile kullanılmak üzere tasarlanmıştır.

+2

gibi std::placeholders kullanarak geçebilir kodunuzda üye işlev

class test{ public: int GetMax(int a, int b); ... } 

olduğunu varsayalım. –

+0

Yup, bu karanlık. :) Yine de, şirket arazisinde bulunan Delphi ve C++ Builder eski kodları var. İyileşmek için en iyisi. – Parappa

5

Standart OO'yu kullanmanız daha iyi olmaz mıydı? Bir sözleşme (sanal sınıf) tanımlayın ve kendi sınıfınızda uygulayın, sonra kendi sınıfınıza bir referans verin ve alıcının sözleşme işlevini çağırmasına izin verin.

sizin örneği kullanarak (I 'buttonAction' için 'dnm2' yöntemini yeniden adlandırdık): alıcı yönteminde

class ButtonContract 
{ 
    public: 
    virtual void buttonAction(); 
} 


class testMenu : public MenuScreen, public virtual ButtonContract 
{ 
    public: 
    bool draw; 
    MenuButton<testMenu> x; 

    testMenu():MenuScreen("testMenu") 
    { 
     x.SetButton(100,100,TEXT("buttonNormal.png"), 
       TEXT("buttonHover.png"), 
       TEXT("buttonPressed.png"), 
       100, 40, &this); 
     draw = false; 
    } 

    //Implementation of the ButtonContract method! 
    void buttonAction() 
    { 
     draw = true; 
    } 
}; 

, size gerçekleştirmek istediğiniz ardından zaman, bir ButtonContract başvurusunu saklamak Butonun eylemi, kaydedilen ButtonContract nesnesinin 'buttonAction' yöntemini çağırır.

+0

gibi bir şey olduğunu belirleyemedi Sorun, bir düğmeyle çağrılabilecek farklı işlevlerin sayısının çok olması, bu görevi çok sıkıcı hale getirmesidir. Bir tuşun muhtemelen arayabileceği 75 ila 100 fonksiyon vardır. –

+0

Bir testMenu *, bir * isA * ilişkisi yerine bir * ButtonContract (veya birçoğu) içerir. Bu yaklaşım, aynı eylemle iki düğmeyi veya farklı eylemlere sahip düğmeleri uygulamakta zorlanır. – mabraham

2

Diğerleri bunu nasıl yapacağınızı size anlattı. ButtonFunc yana

this->ButtonFunc = &ButtonFunc; 

bir parametre, bu kapsamda zaman fonksiyon döner dışına gidecek olan: Ama kimse bu kodun gerçekten tehlikeli olduğunu söylemiştim şaşırdım. Adresini alıyorsun. void (object::**ButtonFunc)() türünde bir değer ( üye işlevine bir işaretçi için işaretçisi) alacak ve bunu bu -> ButtonFunc öğesine atayacaksınız. Bu -> ButtonFunc'i kullanmaya çalıştığınız anda (artık mevcut olmayan) yerel parametrenin depolanmasına erişmeye çalışacaksınız ve programınız muhtemelen çökecektir.

Commodore'un çözümüne katılıyorum.Ama ButtonObj itiraz için işaretçi olduğundan

((ButtonObj)->*(ButtonFunc))(); 

yaptığı hattını değiştirmek zorunda.

6

Bunun çok eski bir konu olduğunu biliyorum. Ama

void SetHandler(Max Handler); 

içine 11

#include <functional> 

senin izni mi fonksiyonu bu şeyi beyan bu

typedef std::function<int(int,int) > Max; 

gibi işlev işaretçisi beyan C++ ile bu işlemek için zarif bir yolu yoktur normal bir işlevi geçirdiğinizi varsayalım, normal

SetHandler(&some function); 

bunu oldukça ... belirsiz bir çözüm var bu

test t; 
Max Handler = std::bind(&test::GetMax,&t,std::placeholders::_1,std::placeholders::_2); 
some object.SetHandler(Handler); 
+1

Bunun için teşekkürler. Yine de bir türünüz var: std :: yer tutucuları, çoğul. – Artfunkel

İlgili konular