بتـــــاريخ : 2/22/2011 9:14:57 PM
الفــــــــئة
  • الحـــــــــــاسب
  • التعليقات المشاهدات التقييمات
    0 874 0


    Expand Your Oop Knowledge موضوع متواضع عن virtual functions

    الناقل : elmasry | العمر :42 | الكاتب الأصلى : Robatic | المصدر : www.arabteam2000-forum.com

    كلمات مفتاحية  :

    السلام عليكم ورحمة الله وبركاته
    كيف الحال يا أخواني الأعزاء

    يا اخواني إن شاء الله في هذا الموضوع راح اتكلم ( إذا سمحتولي ) عن الـ OOP و شوية عن الـ Inheritance
    وكلنا نعرف عنها، لكن راح اتطرق إلى الـ virtual functions بالأخص
    بس قبل كل حاجة خلوني اعطيكم مقدمة بسيطة عن الـ Pointers to Objects

    لو مثلا كان عندنا كلاس بسيط بإسم MyClass ، عشان نعمل منه كائن نكتب التالي

    MyClass someObject


    إلى الآن مافي شيء جديد، طيب لو نريد نعمل كائن ولكن مش أي كائن بل مؤشر، نكتب التالي
    MyClass* obPtr = new MyClass()


    إلى الآن الي عنده خلفية عن الـ Java او الـ C# ما عنده اي مشكلة

    طيب نفرض إنه عندنا كلاسين Base و Derived حيث انه الثاني قام بوراثة الأول، هل العبارة التالية صحيحه ؟؟؟
    Base* ptr = new Derived()


    نعم ( ممكن البعض يتفاجأ ) ولكن خلونا نوضح اكثر، افرض الكلاسين الي تم ذكرهم فوق معرفين بالطريقة التالي :
    class Base
    {
    public:
            void function() { cout << "This is from Base Class\n"; }
    };

    class Derived : public Base
    {
    public:
            void function() { cout << "This is from Derived Class\n"; }
    };

    ودالة الـ main معرفة على النحو التالي :
    void main()
    {
            Base *b = new Base();
            b->function();

            Derived *d = new Derived();
            d->function();
    }


    طبعا الـ output راح يكون كالتالي ( اوه كم مرة كتبت كلمة "التالي" ؟؟ :S )

    This is from Base Class
    This is from Derived Class


    طيب لو أعدنا تعريف الـ main كما يلي ( لازم من التغيير؟؟؟!!!! ):
    void main()
    {
            Base *b = new Derived();
            b->function();
    }


    ماذا ستكون المخرجات ؟؟؟؟؟
    This is from Base


    همممممممم ؟؟ محير !!!!!
    بكل بساطة على الرغم من إنه تم تعديل "Overload" للدالة function ولكن ما زالت تستخدم النسخة الموجود في Base Class بدلا من
    النسخة الموجوده في Derived Class
    لحل هذه المشكلة نقوم بتعريف الدالة function والموجوده في الـ Base على أنها virtual كالتالي

    class Base
    {
    public:
            virtual void function() { cout << "This is from Base Class\n"; }
    };


    ثم نقوم بتنفيذ البرنامج.

    طيب إش الفائدة من هذا الكلام أو كيف ممكن نسخر هذا الكلام لنا ؟؟؟؟
    اقول : إذاذ كان عندنا كلاس A وكان في كلاس ثاني B والكلاس B ورث من الكلاس A فإن الكلاس A هو B والعكس غير صحيح
    يعني نقدر نستخدم مؤشر من نوع A يأشر على B

    خلونا نعدل في الكود تبع الـ Base والـ Derived كالتالي ونضيف دالة خارجية نرسلها Pointer من نوع Base وتقوم بتنفيذ الدالة function
    ونشوف كيف تطلع النتيجة

    #include <iostream>

    using namespace std;

    class Base
    {
    public:
            virtual void function() { cout << "This is from Base Class\n"; }
    };

    class Derived : public Base
    {
    public:
            void function() { cout << "This is from Derived Class\n"; }
    };


    void test(Base* anything) {anything->function();}


    void main()
    {
            Base* p = new Base();
            test(p);

            p = new Derived();
            test(p);
    }


    لو تلاحظوا ناتج المخرجات إنه تم تنفيذ الدالة على حسب مهي معرفة في كل كلاس مع إنه الدالة test ما تستقبل إلا pointer من نوع Base
    بمعنى آخر إحنا قدرنا نعمم الدالة test على كل من Base & Derived.

    كيف يفيدنا هذا التكتيك ؟؟
    خذ السناريو التالي :
    تخيل نفسك شغال في بنك كمبرمج، وقمت بكتابة برنامج الصراف الآلي ATM بحيث انه يستقبل حساب توفير وحساب جاري
    وتحليلك كان كالتالي :
    كتابة كلاس خاص بحساب جاري RegularAccount
    كتابة كلاس خاص بحساب توفير SavingAccount
    والفرق بينهم انه في الـ RegularAccount كان في دالة إسمها withdrawl وهي مسؤولة عن عملية السحب النقدي وتم عمل overload
    لنفس الدالة في الـ SavingAccount بحيث إنه تختلف في حساب معدل الفائدة لكل من الحسابين
    فبدون الـ virtual function راح يكون البرنامج تقريبا كالتالي ( نظريا):
    تحديد نوع الكائن إذا كان RegularAccount أو SavingAccount
    بحيث يتم عمل كائن جديد من نفس النوع ثم قم بتنفيذ الدالة withdrawl

    طيب لو طلب منك المدير إضافة 1000 نوع حساب جديد كيف الحل ؟؟؟!!!!
    على نفس المنطق المذكور أعلاه راح تقوم بكتابة 1000 IF و 1000 سطر لإنشاء كائن و 1000 إستدعاء للدالة withdrawl

    هنا يجيء دور الـ Pure Abstract Class و الـ Virtual Functions
    حيث إنه تقوم بعمل Abstract Class بإسم مثلا Account وفيه الدالة withdrawl معرفة على إنها virtual وبعد كذا قوم بتعريف كلاس لكل حساب ولكن قم بتوريثة للـ Account وقم بتغيير الدالة withdrawl على حسب ما يتناسب لكل نوع حساب
    وبعد ذلك قوم بكتابة دالة عامة تقوم بإستدعاء الدالة withdrawl ولكن عن طريق pointer من نوع Account يتم إرساله لها على النحو التالي

    void doWithdrawl(Account* ob) { ob->withdrawl(); }


    بهذه الطريقة قدرنا نضمن إنه الدالة doWithdrawl راح تقوم بعملية السحب النقدي بشكل صحيح لكل حساب بغض النظر عن نوع الحساب
    وهذا ما يسمى بالـ Generic Programming ونفس الأسلوب ينطبق على الـ Java & CSharp


    إن شاء الله ما اكون لخبطكم وإن شاء الله يكون هذا الدرس مفيد وأتمنى لكم التوفيق

    اخوكم Robatic

    كلمات مفتاحية  :

    تعليقات الزوار ()