سؤال

قل عندي:

void Render(void(*Call)())
{
    D3dDevice->BeginScene();
    Call();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

هذا أمر جيد طالما أن الوظيفة التي أرغب في استخدامها للعرض هي وظيفة أو ملف static وظيفة العضو :

Render(MainMenuRender);
Render(MainMenu::Render);

ومع ذلك، أريد حقًا أن أكون قادرًا على استخدام طريقة الفصل أيضًا لأنه في معظم الحالات، سترغب وظيفة العرض في الوصول إلى متغيرات الأعضاء، وبدلاً من ذلك لا أجعل مثيل الفصل عامًا، على سبيل المثال.

Render(MainMenu->Render);

ومع ذلك، ليس لدي أي فكرة عن كيفية القيام بذلك، وما زلت أسمح بالوظائف و static وظائف الأعضاء التي سيتم استخدامها.

هل كانت مفيدة؟

المحلول

هناك الكثير من الطرق لسلخ هذه القطة، بما في ذلك القوالب.المفضل لدي هو Boost.function حيث وجدت أنها الأكثر مرونة على المدى الطويل.اقرأ أيضًا Boost.bind للربط بوظائف الأعضاء بالإضافة إلى العديد من الحيل الأخرى.

انها تبدو مثل هذا:

#include <boost/bind.hpp>
#include <boost/function.hpp>

void Render(boost::function0<void> Call)
{
    // as before...
}

Render(boost::bind(&MainMenu::Render, myMainMenuInstance));

نصائح أخرى

يمكنك جعل وظيفة المجمع void Wrap(T *t) هذا يدعو فقط t->Call() و لدي Render خذ هذه الوظيفة مع كائن.إنه:

void Wrap(T *t)
{
  t->Call();
}

void Render(void (*f)(T *), T *t)
{
  ...
  f(t);
  ...
}

لقد فعلت ذلك مرة واحدة من خلال تحديد وظيفة عامة "Call" والتي تقبل مؤشرًا إلى حالتك كعضو

void CallRender(myclass *Instance)
{
  Instance->Render();
}

لذلك يصبح التقديم:

void Render(void (*Call)(myclass*), myclass* Instance)
{
  ...
  Call(Instance);
  ...
}

ومكالمتك لتقديم هي:

Render(CallRender, &MainMenu);

أعلم أنه قبيح، لكنه نجح بالنسبة لي (كنت أستخدم خيوط pthreads)

لا يمكنك استدعاء وظيفة عضو من مؤشر ما لم يكن لديك مرجع للكائن أيضًا.على سبيل المثال:

((object).*(ptrToMember))

لذلك لن تتمكن من تحقيق ذلك دون تغيير توقيع طريقة العرض الخاصة بك. هذا تشرح المقالة لماذا تعتبر هذه فكرة سيئة بشكل عام.

قد تكون الطريقة الأفضل هي تحديد واجهة "Renderer" التي يمكن لفئاتك التي تحتوي على طرق عرض أن تنفذها وتكون نوع المعلمة لطريقة العرض الرئيسية الخاصة بك.يمكنك بعد ذلك كتابة تطبيق "StaticCaller" لدعم استدعاء الأساليب الثابتة الخاصة بك حسب المرجع.

على سبيل المثال (إن برنامج C++ الخاص بي صدئ حقًا، ولم أقم بتجميع هذا أيضًا).



void Render(IRenderer *Renderer)
{
    D3dDevice->BeginScene();
    Renderer->Render();
    D3dDevice->EndScene();
    D3dDevice->Present(0,0,0,0);
}

// The "interface"
public class IRenderer 
{
public:
    virtual void Render();
};

public class StaticCaller: public IRenderer
{
    void (*Call)();
public:

    StaticCaller((*Call)())
    {
        this->Call = Call;
    }

    void Render()
    {
        Call();
    }
};

كل هذا نموذجي جدًا ولكنه يجب أن يجعل القراءة أكثر سهولة.

يمكنك إعلان مؤشر دالة لوظيفة عضو من الفئة T باستخدام:

typedef void (T::*FUNCTIONPOINTERTYPE)(args..)
FUNCTIONPOINTERTYPE function;

واستدعاءه كالآتي:

T* t;
FUNCTIONPOINTERTYPE function;
(t->*function)(args..);

إن استقراء ذلك في نظام الكاري المفيد باستخدام الوسائط والأنواع وقيم الإرجاع المتغيرة، وما إلى ذلك، أمر رتيب ومزعج.لقد سمعت أشياء جيدة عن مكتبة التعزيز المذكورة أعلاه، لذا أوصي بالبحث في ذلك قبل القيام بأي شيء جذري.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top