الفئات المرمزة في ++C

الفئات المرمزة

c

يمكن استغلال إمكانية التعريف الرمزي للبيانات مع الفئات , ويكون ذلك مفيدا بصفة خاصة لهياكل البيانات التي تعمل كحاويات لها كالمكادس والقوائم المترابطة . فما قدمناه من أمثلة لهذه الحاويات لا تضم إلا نوعا واحدا من البيانات , فالمكدس المعطي في الفصل 8 مثلا لا يضم إلا العدد الصحيح . ولو أردنا مكدسا لنوع أخر فلابد من صياغة خاصة له . ولكم يكون حسنا لو أننا تمكنا من أن نضع صياغة واحدة تنفع لكل الأنواع .

وكما نراك قد خمنت , يأتي أسلوب ترميز البيانات ليعطينا هذه الإمكانية . إليك الأن صياغة جديدة للبرنامج stackay يأخذ بأسلوب التعريف الرمزي .

Tempstak.cpp

// tempstak.cpp


// implements stack class as a template


// UCS Laboratories


 


#include <iostream.h>


const int MAX = 100;


 


template <class Type>


class Stack


   {


   private:


        Type st[MAX];             // stack: array of any type


      int top;                  // number of top of stack


   public:


        Stack()                   // constructor


            { top = -1; }


      void push(Type var)       // put number on stack


            { st[++top] = var; }


      Type pop()                // take number off stack


         { return st[top--]; }


   };


 


void main()


   {


   Stack<float> s1;      // s1 is object of class Stack<float>


 


   s1.push(1111.1);      // push 3 floats, pop 3 floats


   s1.push(2222.2);


   s1.push(3333.3);


   cout << "1: " << s1.pop() << endl;


   cout << "2: " << s1.pop() << endl;


   cout << "3: " << s1.pop() << endl;


 


   Stack<long> s2;       // s2 is object of class Stack<long>


 


   s2.push(123123123L);  // push 3 longs, pop 3 longs


   s2.push(234234234L);


   s2.push(345345345L);


   cout << "1: " << s2.pop() << endl;


   cout << "2: " << s2.pop() << endl;


   cout << "3: " << s2.pop() << endl;


    }


 


 




 





في هذا المثال تكون الفئة stack فئة مرمزة حيث استخدم في تعريف البيان st[MAX] بها النوع الرمزي type , وهي بذلك تصلح كنمط لمحول الصياغة كي ينشئ علي غرارها فئات تصلح للأنواع المختلفة ] ومن ثم كان اسمها class template بمعني "الفئة النمطية" أو نمط فئة [ . وتري الرمز type قد استخدم في البرنامج في ثلاثة مواضيع , في تعريف المصفوفة st , وفي معامل الدالة push() وفي نوع البيان المعاد من الدالة pop() .




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



Stack<float> s1;



Stack<long> s2;



وهكذا ويبين هذا الأسلوب في تعريف الفئات وإنشاء الكائنات .



 



Friend void Tee(Component&, Component&)



};



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



المؤثر "تدفق إلي "



يقوم المؤثر " تدفق إلي " بتوصيل عنصرين متتالين في مسار التدفق . هنا يساوي بين خصائص الدخول الثلاثة للعنصر السابق بمثيلاتها للعنصر اللاحق علي النحو التالي :



// ''flow into'' operator: c1 >= c2



Void operator >=(Component& c1, Component& c2)



{



C2.inpress = c1.outpress;



C1.inbackp = c2.inbackp;



C2.inflow = c1.out.flow;



}



وقد عرفت دالة المؤثر علي أنها صديقة , وكان من الممكن تعريفها كدالة منتمية , ولكن دالة أخري ؛ Tee() , يجب أن تعرف كدالة صديقة , ومن ثم فقد عرفت دالة المؤثر كدالة صديقة لأجل التوافق . وقد جعل الإمرار في دالة المؤثر مرجعيا , حيث إن المعاملين ذاتها يجب تغييرهما معا .



وحيث إن المؤثر >= يطبق علي كائنات الفئة الأساسية فهو يطبق بالتبعية علي كائنات الفئات المشتقة كالتنكات والصمامات , ويوفر عليك ذلك جهد تعريف دالة لتتعامل مع كل نوع من التوصيلات , فمثلا :



Friend void



operator >= (Pipe&, Valve&);



Friend void operator >= (Valve&, Tank&);



Friend void operator



>= (Valve&, Sink&);



وهكذا .



الفئات المشتقة



لدينا الفئات المشتقة التالية : Source, Sink, Pipe, Valve, Tank , لكل فئة خصائصها الذاتية فالفئة Source ذات ضغط ثابت , بينما sink ذات ضغط مضاد ثابت والفئة Pipe ذات مقاومة داخلية ثابتة , ومن ثم فلا يمكن للضغط المضاد لها أن يكون أكبر مقدار معين . وتتميز الفئة Valve بوضعين يعرفان كبيانات معددة enum من النوع offon : وهما on,off للمتغير status والفئة Tank قيمة تعبر عن حجم الماء المختزن . وتتغير حالة الصمامات , وسعة التنكات , مع سريان البرامج .



وبالنسبة للبيانات الثابتة , مثل مقاومة المواسير أو ضغط المصدر , فهي تستهل مع إنشاء الكائن .



ونلاحظ أن كل هذه العناصر , وكذا العنصر switch تحتوي علي دالة توقيت Tick() , تستدعي علي فترات ثابتة لتحديث وضع كل عنصر , واحدا بعد الأخر.



الدالة Tee()



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



وتستدعي هذه الدالة بثلاثة عوامل , بالترتيب التالي :



Tee(input1, output1, outut2);



وللأسف ليس بإمكاننا أن نزيد تحميل مؤثر ليؤدي هذه المهمية كما فعلنا مع التوصيل المعتاد لتكون الصياغة أكثر رشاقة , وذلك لا يوجد مؤثر ثلاثي التأثير ] عدا المؤثر الشرطي "؟" [ .



الفئة switch



الفئة switch لها علاقة خاصة بالفئة Tank , فكل تانك لو سويتشان , يعمل أحدهما حين تنخفض سعة التانك عن مستوي معين , والأخر حين تزيد عن حد معين .



فلنعبر عن هذه العلاقة الخاصة بين التانك وسوتشيه بقولنا أن التانك "يحوز own" السوتشين فحين ينشأ سويتش يلحق به قيمتان أحدهما عنوان التانك الذي يحوزه , templist2.cpp



وقد استخدمنا في البرنامج متغيرا احتياطيا emptemp يخزن فيه البيان قبل إضافته للقائمة . و تلاحظ أننا لم نحتج لأي تعديل في صياغة الفئة LinkList في هذا البرنامج , وهذا مكمن الجمال في أسلوب الترميز , فهي تعمل مع البيانات الأولية والبيانات التي يضعها المبرمج علي حد سواء .



ولكن عليك أن تلاحظ أنه في حالة وجود مؤثر في إحدي دوال فئة التخزين لا يعمل مع نوع من أنواع البيانات , فإن الفئة لن يمكنها أن تخزنه .

التسميات: