الفئات المرمزة في ++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 في هذا البرنامج , وهذا مكمن الجمال في أسلوب الترميز , فهي تعمل مع البيانات الأولية والبيانات التي يضعها المبرمج علي حد سواء .
ولكن عليك أن تلاحظ أنه في حالة وجود مؤثر في إحدي دوال فئة التخزين لا يعمل مع نوع من أنواع البيانات , فإن الفئة لن يمكنها أن تخزنه .
تعليقات
إرسال تعليق