سؤال

typedef void (FunctionSet::* Function)();

class MyFunctionSet : public FunctionSet
{
protected:
    void addFunctions()
    {
        addFunction(Function(&MyFunctionSet::function1));
    }

    void function1()
    {
        // Do something.
    }
};

وطريقة addFunction يضيف وظيفة إلى قائمة في الفئة الأساسية،
ومن ثم يمكن المذكورة لدعوة جميع وظائف.

هل هناك أي طريقة لتبسيط (عمل أقل الكتابة) وإضافة وظائف؟

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

المحلول

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

لإجابة السؤال الفعلي - وأود أن جعل addFunction قالب:

void addFunctions() {
    addFunction(&MyFunctionSet::function1);
}

تغيير addFunction في الدرجة الأساس لهذه:

template<typename Derived>
void addFunction(void(Derived::*f)()) {
    myFunctions.push_back(static_cast<Function>(f));
}

وأفضل استخدام static_cast، لأنها سوف أقول لكم إن لم يكن مشتق Derived فعلا من FunctionSet.

نصائح أخرى

هل يمكن ان توضح ما نحاول تحقيقه من خلال ذلك؟

وهذا يبدو وكأنه تصميم سيئة إلى حد ما، لا يمكن أن يكون لديك فئة مجردة ( "ج ++ واجهة") مثل "محسوب" الذي يحتوي على function1، والظاهري النقي، وفئة فرعية محسوب لكل تطبيق، ومن ثم يكون MyFunctionSet الحفاظ على مجموعة من محسوب؟

هل هناك سبب معين كنت تستخدم مؤشرات الدالة؟

وهكذا، فإنني أميل إلى اختلف مع أوري، إلى حد ما.

إذا كنت تنفيذ نمط المراقب، ما أريده هو أن تكون قادرة على القول:

وقال "عندما كائن X لا Y، أريد أن تنفيذ التعليمات البرمجية Z".

والذهاب مع نهج يستند كليا على فئة مجردة ليست أفضل طريقة للقيام بذلك. تتطلب فئة منفصلة (وخصوصا في C ++) لكل معالج الحدث هو مبالغة. إذا كنت قادما من جاوة، هذه هي الطريقة التي تفعل كل شيء. ومع ذلك جافا 2 الميزات التي تجعل هذا فقط مزعج قليلا: فئة مجهولة المصدر، و "المثال" الطبقات الأعضاء. هذا يسمح لك لتحديد معالجات متعددة لأحداث متعددة في نفس الفئة. لديك بادئة الطرق مع "الطبقة {"، ولكن يمكنك أن تفعل ذلك.

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

و. NET يستخدم المندوبين للتعامل مع الحدث، والتي هي في الأساس نوع مؤشرات الدالة آمنة. أنها تجعل رمز للتعامل مع الأحداث مباشرة جدا الى الامام. وخلافا للمؤشرات الدالة في C ++، ومع ذلك، وهو مندوب يوحد مؤشرات الدالة الأعضاء ومؤشرات الدالة ثابتة. أساسا يمكن أن الكاري على "هذا" المعلمة في أي وظيفة الأعضاء، ترك مؤشرات الدالة التي تبدو تماما مثل مؤشر دالة ثابتة. وهذا يعني أن هذا النوع من التعامل مع الحدث وجوه ليست جزءا من "واجهة" الحدث. أن يجعلها مرنة للغاية.

وأنت لا تستطيع أن تفعل ذلك مباشرة باستخدام C ++ المؤشرات الدالة العضو لأن "هذا" نوع ينتهي به الأمر جزء من وظيفة نوع المؤشر، مما يحد من معالجات لتظهر فقط داخل الطبقة الحالية.

وأفضل حل لC ++ هو مزيج بين الاثنين. ما تريده هو واجهة عامة مثل هذا:

class EventHandler
{
public:
    virtual void Handle() = 0;
};

وبعد ذلك تنفيذ لوظائف الأعضاء، مثل هذا

template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:


    MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
    {
    }

    void Handle()
    {
        (m_pThis->*m_pFunc)();
    } 
private:
    T* m_pThis;
    void (T::*m_pFunc)();
};

template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
    return new MemberFuncEventHandler<T>(pThis, pFunc);
}

ويمكنك أيضا تحديد بالمثل فئة معالج لأساليب ثابتة. ثم يمكنك القيام به مجرد أشياء من هذا القبيل:

Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...

هل يمكن أن تفرط في المشغل بالإضافة إلى ذلك، أفترض.

إذا كنت تحاول أن تجعل نظام الاستدعاء أو شيء أود أن أوصي مكتبة Boost.Signals. في الأساس هو يجمع وظائف وتدعو المجموعة الدالة على الأوامر (مثل أي مكتبة إشارة أخرى) ولكن كما أنها مصممة للعمل مع Boost.Bind وBoost.Function التي هي رهيبة.

مثال:

using boost::function
using boost::bind
using boost::signal

void some_other_func();    

Foo a;
Bar b;

signal<void()> sig;

sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);

sig(); // calls -> a.foo(), b.bar(), some_other_func()

ويدعم أيضا حظر، إدارة الاتصال المتطورة وغيرها من الأشياء الرائعة.

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