زيادة تحميل المؤثرات الثنائية في ++C

زيادة تحميل المؤثرات الثنائية

المؤثرات الحسابية

في برنامج englcon.cpp بالمقالات السابقة استخدمنا الدالة add_dist() لكي يمكننا جمع مسافتين , بالأمر :

Dist3.add_dist(dist, dist);

وسوف نعيد صياغة البرنامج بزيادة تحميل المؤثر "+" حتي يمكننا وضع الأمر علي الصيغة :

Dist3 = dist1 + dist2;

englplus.cpp


 


// englplus.cpp


// overloaded '+' operator adds two Distances


// UCS Laboratories


#include <iostream.h>


#include <conio.h>


 


class Distance                    // English Distance class


   {


   private:


      int feet;


      float inches;


   public:


      Distance()                  // constructor (no args)


     { feet = 0; inches = 0.0; }


      Distance(int ft, float in)  // constructor (two args)


     { feet = ft; inches = in; }


 


      void getdist()              // get length from user


     {


     cout << "\nEnter feet: ";  cin >> feet;


     cout << "Enter inches: ";  cin >> inches;


     }


 


      void showdist()             // display distance


     { cout << feet << "\'-" << inches << '\"'; }


 


      Distance operator + ( Distance );  // add two distances


   };


                  // add this distance to d2


Distance Distance::operator + (Distance d2)   // return the sum


   {


   int f = feet + d2.feet;        // add the feet


   float i = inches + d2.inches;  // add the inches


   if(i >= 12.0)                  // if total exceeds 12.0,


      {                           // then decrease inches


      i -= 12.0;                  // by 12.0 and


      f++;                        // increase feet by 1


      }                           // return a temporary Distance


   return Distance(f,i);          // initialized to sum


   }


 


void main()


   {


   Distance dist1, dist3, dist4;   // define distances


   dist1.getdist();                // get dist1 from user


              


   Distance dist2(11, 6.25);       // define, initialize dist2


 


   dist3 = dist1 + dist2;          // single '+' operator


 


   dist4 = dist1 + dist2 + dist3;  // multiple '+' operators


 


                   // display all lengths


   cout << "\ndist1 = ";  dist1.showdist();


   cout << "\ndist2 = ";  dist2.showdist();


   cout << "\ndist3 = ";  dist3.showdist();


   cout << "\ndist4 = ";  dist4.showdist();


   getche();


   }




وفي هذا البرنامج كان الإعلان عن دالة زيادة تحميل المؤثر , علي الصورة :



Distance operator + (distance):



ثم كان تعريف الدالة خارج الفئة وهي دالة تأخذ معاملا هو كائن من الفئة distance وتعيد كائنا بنفس الفئة .



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



Object-Oriented Programming in C   _Page_0357_Image_0001





شكل المؤثر الثنائي – معامل واحد



جمع الإحداثيات القطبية



يبين الشكل طريقة تعيين النقاط بالإحداثيات الكارتيزية ( البعد السيني والبعد الصادي ) وشكل أسلوب الإحداثيات القطبية (المسافة وزاوية الانحراف ) . ويبين الشكل طريقة جمع هذه الإحداثيات , أما الشكل فيبين طريقة جمع الإحداثيات الكارتيزية . ويبين الشكل العلاقة بين نظامي الإحداثيين .



Collection of polar coordinates



شكل الإحداثيات الكارتيزية



Coordinates collection Rtezih



شكل الإحداثيات القطبية



Coordinates Rtezih



شكل جمع الإحداثيات القطبية



Polar coordinates



شكل جمع الإحداثيات الكارتيزية



The relationship between the two systems and polar Rtezih



شكل العلاقة بين النظامين



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



X = radius*cos(angle);



Y = radius*sqrt(x*x + y*y);



أما التحويل العكسي :



angle = atan(y/x);



radius = sqrt(x*x) + y*y);



وتوجد في لغة السي ++ دوال مكتبية لإيجاد مع كل من sin, cos, atan للزوايا .



وإليك البرنامج .






polaplus.cpp


 


// polaplus.cpp


// operator '+' with polar coordinates


// UCS Laboratories


#include <iostream.h>


#include <math.h>            // for sin(), cos(), etc.


#include <conio.h>


 


class Polar


   {


   private:


      double radius;                     // distance


      double angle;                      // angle in radians


 


      double getx()                      // these two functions


     { return radius*cos(angle); }   // convert this Polar


      double gety()                      // object into x and y


     { return radius*sin(angle); }   // rectangular coords


   public:


      Polar()                            // constructor, no args


     { radius=0.0; angle=0.0; }


      Polar(double r, double a)          // constructor, two args


     { radius=r; angle=a; }


      void display()                     // display


     { cout << "("  << radius


        << ", " << angle << ")"; }


      Polar operator + (Polar p2)        // add two Polars


     {


     double x = getx() + p2.getx();  // add x and y coords


     double y = gety() + p2.gety();  // for this and p2


     double r = sqrt(x*x + y*y);     // convert new x and y


     double a = atan(y/x);           // to Polar


     return Polar(r, a);             // return temp Polar


     }


   };


 


void main()


   {


   Polar p1(10.0, 0.0);            // line to the right


   Polar p2(10.0, 1.570796325);    // line straight up


   Polar p3;                       // uninitialized Polar


 


   p3 = p1 + p2;                   // add two Polars


 


   cout << "\np1="; p1.display();  // display all Polars


   cout << "\np2="; p2.display();


   cout << "\np3="; p3.display();


   getche();


   }




تحتوي الفئة polar علي بيانين radius, angle , وقد عرفا double هو النوع الذي تتعامل معه غالبا المكتبية الرياضية , وتقاس الزوايا بالتقدير القطري radians . وتضم الفئة بادئتين , واحد للاستهلال الصفري والأخر للاستهلال بالقيم , ودالة للإظهار كما توجد دالتين لتحويل الإحدثيات القطبية إلي كارتيزية , هما getx() و gety() وقد جعلا خاصين , حيث لا يلزم استدعاؤها من خارج الفئة .



وتقوم دالة المؤثر operator+ بجمع إحداثيات قطبيين معا ويمكن بنفس المنطق زيادة تحميل بقية المؤثرات الحسابية لتعمل مع الإحداثيات القطبية .



وصل العبارات النصية



لا يمكن في لغة السي استخدام المؤثر "+" لوصل العبارات النصية concatenation string كما في لغات غيرها , ولكن باستخدام كائن العبارة النصية في برنامج strobj.cpp  , وزيادة تحميل المؤثر المذكور , يمكننا تحقيق ذلك وإليك البرنامج :






strplus.cpp


 


// strplus.cpp


// overloaded '+' operator concatenates strings


// UCS Laboratories


#include <iostream.h>


#include <string.h>     // for strcpy(), strcat()


#include <stdlib.h>     // for exit()


#include <conio.h>


 


const int SZ = 80;       // size of all String objects


 


class String             // user-defined string type


   {


   private:


      char str[SZ];                  // holds a string


   public:


      String()                       // constructor, no args


     { strcpy(str, ""); }


      String( char s[] )             // constructor, one arg


     { strcpy(str, s); }


      void display()                 // display the String


     { cout << str; }


      String operator + (String ss)  // add a String to another


     {


     String temp;             // make a temporary String


     if( strlen(str) + strlen(ss.str) < SZ )


        {


        strcpy(temp.str, str);   // copy this string to temp


        strcat(temp.str, ss.str);  // add the argument string


        }


     else


        { cout << "\nString overflow"; exit(1); }


     return temp;            // return temp String


     }


   };


 


void main()


   {


   String s1 = "\nMerry Christmas!  ";   // uses constructor 2


   String s2 = "Happy new year!";        // uses constructor 2


   String s3;                            // uses constructor 1


 


   s1.display();         // display strings


   s2.display();


   s3.display();


 


   s3 = s1 + s2;         // add s2 to s1, assign to s3


 


   s3.display();         // display s3


   getche();


   }




يظهر البرنامج أولا ثلاث عبارات نصية , (الثالثة فارغة) , ثم يوصل الأولي والثانية , و يوضعها في العبارة الثالثة , ثم يظهرها .



والمفروض أن يكون تحميل المؤثر مألوفا الأن , فالإعلان :



String operator + (string ss)



يبين أن المؤثر يأخذ معاملا من النوع string , ويعيد قيمة من نفس النوع . وتتضمن عملية الوصل إنشاء كائن مؤقت temp , ثم نسخ العبارة المتضمنة في كائننا فيه , ووصلها بالعبارة التي في المعامل باستخدام الدالة المكتبية strcat() , ثم إعادة القيمة بعد الوصل .



وليس بإمكاننا استخدام أسلوب الكائن المؤقت غير المسمي (راجع برنامج countpp3.cpp ):



Return string (string);



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



زيادة التحميل المتعدد



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



مؤثرات المقارنة سوف نقوم الأن بزيادة تحميل نوع أخر من المؤثرات , مؤثرات المقارنة .



مقارنة المسافات



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






engless.cpp


 


// engless.cpp


// overloaded '<' operator compares two Distances


// UCS Laboratories


#include <iostream.h>


#include <conio.h>


 


enum boolean { false, true };


 


class Distance                    // English Distance class


   {


   private:


      int feet;


      float inches;


   public:


      Distance()                  // constructor (no args)


     { feet = 0; inches = 0.0; }


      Distance(int ft, float in)  // constructor (two args)


     { feet = ft; inches = in; }


      void getdist()              // get length from user


     {


     cout << "\nEnter feet: ";  cin >> feet;


     cout << "Enter inches: ";  cin >> inches;


     }


      void showdist()             // display distance


     { cout << feet << "\'-" << inches << '\"'; }


      boolean operator < (Distance);  // compare distances


   };


                 // compare this distance with d2


boolean Distance::operator < (Distance d2)   // return the sum


   {


   float bf1 = feet + inches/12;


   float bf2 = d2.feet + d2.inches/12;


   return (bf1 < bf2) ? true : false;


   }


 


void main()


   {


   Distance dist1;                 // define Distance dist1


   dist1.getdist();                // get dist1 from user


 


   Distance dist2(6, 2.5);         // define and initialize dist2


                   // display distances


   cout << "\ndist1 = ";  dist1.showdist();


   cout << "\ndist2 = ";  dist2.showdist();


 


   if( dist1 < dist2 )             // overloaded '<' operator


      cout << "\ndist1 is less than dist2";


   else


      cout << "\ndist1 is greater than dist2";


   getche();


   }




ويشابه أسلوب زيادة تحميل المؤثر < ما كان بالنسبة بالمؤثر +, عدا أن دالة المؤثر تعيد قيمة من النوع Boolean المعرفة في صدر البرنامج بواسطة المستخدم enum , تضم حالتين true, false لتمثل متغيرا منطقيا هذه القيمة المعادة هي نتيجة المقارنة , ويتم تحويل المسافتين إلي كسر عشري قبل إجراء المقارنة .



ونذكرك بأن العبارة :



Return (bf1 < bf2 ) ? true : false;



هي أوامر مختصر للأوامر :



If (bf1 < bf2)



Return true;



Else



Return false;



مقارنة عبارتين



إليك برنامجا أخر لمقارنة عبارتين , لنعرف تطابقهما من عدمه , وسوف نستخدم مؤثر التساوي "= =" .






strequal.cpp


 


// strequal.cpp


// overloaded '==' operator compares strings


// UCS Laboratories


#include <iostream.h>


#include <string.h>      // for strcmp()


#include <conio.h>


 


const int SZ = 80;       // size of all String objects


enum boolean { false, true };


 


class String             // user-defined string type


   {


   private:


      char str[SZ];                    // holds a string


   public:


      String()                         // constructor, no args


     { strcpy(str, ""); }


      String( char s[] )               // constructor, one arg


     { strcpy(str, s); }


      void display()                   // display a String


     { cout << str; }


      void getstr()                    // read a string


     { cin.get(str, SZ); }


      boolean operator == (String ss)  // check for equality


     {


     return ( strcmp(str, ss.str)==0 ) ? true : false;


     }


   };


 


void main()


   {


   String s1 = "yes";


   String s2 = "no";


   String s3;


 


   cout << "\nEnter 'yes' or 'no': ";


   s3.getstr();                          // get String from user


 


   if(s3==s1)                            // compare with "yes"


      cout << "You typed yes\n";


   else if(s3==s2)                       // compare with "no"


      cout << "You typed no\n";


   else


      cout << "You didn't follow instructions\n";


   getche();


   }




يستخدم المؤثر "= =" في دالته الدالة المكتبية strcmp() ] اختصار لــــ string compare [ لإجراء المقارنة , وهي تعيد 0 إذا كانت العبارتان متساويتان , وإشارة سالبة إن كانت الأولي أقل من الثانية , وموجبة في حالة العكس , ولفظ " أقل " و " أكبر " يؤخذ بمعني الأسبقية في القاموس اللغوي .



ويمكن استخدام مؤثرات مثل < , > , أو مقارنة أطوال العبارات بحسب ما يريد المبرمج .



مؤثرات التخصيص الحسابية



ننهي حديثنا عن المؤثرات الثنائية بالمؤثر "=+", وهو يقوم بعمليتي الجمع والتخصيص معا . وسوف نستخدمه لجمع مسافتين , ثم تخصيص الناتج للمسافة الأولي . وهو مماثل للبرنامج englplus.cpp مع اختلاف دقيق .






englpleq.cpp


 


// englpleq.cpp


// overloaded '+=' assignment operator


// UCS Laboratories


#include <iostream.h>


#include <conio.h>


 


class Distance                     // English Distance class


   {


   private:


      int feet;


      float inches;


   public:


      Distance()                   // constructor (no args)


     { feet = 0; inches = 0.0; }


      Distance(int ft, float in)   // constructor (two args)


     { feet = ft; inches = in; }


      void getdist()               // get length from user


     {


     cout << "\nEnter feet: ";  cin >> feet;


     cout << "Enter inches: ";  cin >> inches;


     }


      void showdist()              // display distance


     { cout << feet << "\'-" << inches << '\"'; }


      void operator += ( Distance );


   };                                     


                   // add distance to this one


void Distance::operator += (Distance d2)


   {


   feet += d2.feet;                // add the feet 


   inches += d2.inches;            // add the inches


   if(inches >= 12.0)              // if total exceeds 12.0,


      {                            // then decrease inches


      inches -= 12.0;              // by 12.0 and


      feet++;                      // increase feet


      }                            // by 1


   }


 


void main()


   {


   Distance dist1;                 // define dist1


   dist1.getdist();                // get dist1 from user


   cout << "\ndist1 = ";  dist1.showdist();


 


   Distance dist2(11, 6.25);       // define, initialize dist2


   cout << "\ndist2 = ";  dist2.showdist();


 


   dist1 += dist2;                 // dist1 = dist1 + dist2


   cout << "\nAfter addition,";


   cout << "\ndist1 = ";  dist1.showdist();


   getche();


   }




في هذا البرنامج تتم عملية الجمع بالأمر :



Dist1 +=dist2;



ولك أن تلاحظ الفرق بين دالتي المؤثر operator+= والمؤثر operator+ ففي الدالة الأخيرة تطلب الأمر إنشاء كائن ثالث dist3 لوضع ناتج الجمع فيه , معاد من الدالة إذا أردت استخدام هذا المؤثر في عمليات أكثر تعقيدا , علي النحو التالي مثلا :



Dist3 = dist1 += dist2;



فعليك أن تجعل الدالة من النوع الذي يعيد قيمة , وبأن تنهيها بالأمر :



Return distance(feet, inches);



حيث يخلق كائن مؤقت بلا اسم لغرض الإعادة .



مؤثر الأدلة



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



1- دالة للإدخال ودالة للإخراج :






arrover1.cpp


 


// arrover1.cpp


// creates safe array (index values are checked before access)


// uses separate put and get functions


// UCS Laboratories


 


#include <iostream.h>


#include <process.h>        // for exit()


#include <conio.h>


 


const int LIMIT = 100;      // array size


 


class safearay


    {


    private:


        int arr[LIMIT];


    public:


        void putel(int n, int elvalue)


            {


            if( n< 0 || n>=LIMIT )


                { cout << "\nIndex out of bounds"; exit(1); }


            arr[n] = elvalue;


            }


        int getel(int n)


            {


            if( n< 0 || n>=LIMIT )


                { cout << "\nIndex out of bounds"; exit(1); }


            return arr[n];


         }


    };


 


void main()


    {


    safearay sa1;


 


    for(int j=0; j<LIMIT; j++)  // insert elements


        sa1.putel(j, j*10);


 


    for(j=0; j<LIMIT; j++)      // display elements


      {


      int temp = sa1.getel(j);


      cout << "\nElement " << j << " is " << temp;


      }


   getche();


    }




في هذا البرنامج استخدمنا دالة للإدخال pute() ذات معاملين , هما دليل المصفوفة n وعناصرها elvalue وكلاهما من النوع int , والدالة لا تعيد قيما . كما استخدمنا دالة لإظهار العناصر علي الشاشة , هي الدالة gete() وهي تأخذ معاملا واحدا هو دليل المصفوفة , ثم تعيد قيمة العنصر المقابل لذلك الدليل إلي الدالة الأصلية ليخصص للمتغير temp الذي ستظهر قيمته علي الشاشة .



وتتولي دوارة إدخال القيم للمصفوفة ودوارة لإظهارها علي الشاشة .



2- دالة واحدة بالإعادة بالإشارة






arrover2.cpp


 


// arrover2.cpp


// creates safe array (index values are checked before access)


// uses one access() function for both put and get


// UCS Laboratories


 


#include <iostream.h>


#include <process.h>        // for exit()


#include <conio.h>


 


const int LIMIT = 100;      // array size


 


class safearay


    {


    private:


        int arr[LIMIT];


    public:


        int& access(int n)    // note: return by reference


            {


            if( n< 0 || n>=LIMIT )


                { cout << "\nIndex out of bounds"; exit(1); }


            return arr[n];


         }


    };


 


void main()


    {


    safearay sa1;


 


    for(int j=0; j<LIMIT; j++)   // insert elements


        sa1.access(j) = j*10;     // *left* side of equal sign


 


    for(j=0; j<LIMIT; j++)       // display elements


      {


      int temp = sa1.access(j); // *right* side of equal sign


      cout << "\nElement " << j << " is " << temp;


      }


   getche();


    }




في هذه الدالة استخدمنا دالة واحدة هي access() مكان الدالتين , وهو تماثل الدالة gete() عدا أن الإعادة فيها غير مباشرة (لاحظ المؤثر & قبل اسم الدالة ) وبمراجعه ما قلناه عن الإعادة بالإشارة في الفصل السادس , فإن هذا الأسلوب يتيح لنا أن نخصص قيمة للدالة , وهو ما فعلناه بالأمر :



Sa1.access(j) = j*10;



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



ويتقبل الدالة هذه القيم تملأ عناصر المصفوفة , ثم تظهر بالطريقة التي تمت في البرنامج الأول .



3- مؤثر الأدلة بزيادة التحميل






arrover3.cpp


 


// arrover3.cpp


// creates safe array (index values are checked before access)


// uses overloaded [] operator for both put and get


 


#include <iostream.h>


#include <process.h>        // for exit()


#include <conio.h>


 


const int LIMIT = 100;      // array size


 


class safearay


    {


    private:


        int arr[LIMIT];


    public:


        int& operator [](int n)  // note: return by reference


            {


            if( n< 0 || n>=LIMIT )


                { cout << "\nIndex out of bounds"; exit(1); }


            return arr[n];


         }


    };


 


void main()


    {


    safearay sa1;


 


    for(int j=0; j<LIMIT; j++)  // insert elements


        sa1[j] = j*10;           // *left* side of equal sign


 


    for(j=0; j<LIMIT; j++)      // display elements


      {


      int temp = sa1[j];       // *right* side of equal sign


      cout << "\nElement " << j << " is " << temp;


      }


   getche();


    }




حل المؤثر هنا محل الدالة access() في البرنامج السابق , مستفيدا أيضا بإمكانية الإعادة غير المباشرة (بالإشارة) . والمكسب هنا أن صيغة المصفوفة أخذت شكلها المعتاد sa1[j] في أوامر البرنامج .

تعليقات

المشاركات الشائعة من هذه المدونة

المؤثرات الحسابية في C++

الرسم Graphics

دوال النمط الرسومي في ++C