Преоптоварување на оператор

Во компјутерското програмирање преоптоварување на операторот (помалку познато како ad-hoc полиморфизам) е специфичен случај на полиморфизам во кој некој или сите оператори како +, =, ==, new или [] имаат различни имплементации во зависност од видот на аргументот. Понекогаш преоптоварувањата се дефинирани од јазикот; понекогаш програмерот може да преименува поддршка за нови видови. Понекогаш преоптоварувањето е корисно бидејќи му овозможува на програмерот да програмира користејќи нотација која е поблиску до целта на проблемот и му овозможува на корисникот на типови да изгледа како типот да е вграден во јазикот. Ова може лесно да се емулира користејќи повикување на функција; На пример, земајќи ги целите броеви a, b, c:

a + b * c

Во јазик каде операторот „*“ има поголем приоритет од „+“ има поудобен начин на пишување:

add (a, multiply (b,c))

Како и да е во C++ обрасците и дури во макрата во Ц, преоптаварување на операторот е потребно за пишување на генерички, првобитни операции како што се собирање на елементите кога се спроведува образец на вектор. Единствениот начин да се напише првобитно собирање е a + b и ова работи за сите видови на елементи само поради преоптоварувањето на операторот. (Односно во C++ може да се дефинира преоптоварена функција и да се користи add наместо, но не и во C.)

Поопшта варијанта на преоптоварување на операторот таканаречена „Намалување на изразот“, им овозможува на изразите кои содржат еден или повеќе оператори да бидат намалени до една функција. Изразот погоре може дабиде намален до:

operator_add_and_multiply_integers(a, b, c)

Пример уреди

Во овој случај операторот за собирање е преоптоварен за да овозможи додавање на дефинираниот вид „Time“. Примерот е во C++:

 class Time{
   ...
   ...
   ...

   public:
     Time operator+(const Time& lhs, const Time& rhs);  // Операторот за собирање на два објекта од типот Time е деклариран 
                                                        // како пријателска функција за класата Time, овозможувајќи му пристап до
                                                        // сите видови атрибути и методи од таа класа, без разлика дали се 
                                                        // јавни(public), приватни(private) или заштитени(protected)
 }

 Time operator+(const Time& lhs, const Time& rhs)
 {
   Time temp = lhs;
   temp.seconds += rhs.seconds;
   if (temp.seconds >= 60)
   {
     temp.seconds -= 60;
     temp.minutes++;
   }
   temp.minutes += rhs.minutes;
   if (temp.minutes >= 60)
   {
     temp.minutes -= 60;
     temp.hours++;
   }
   temp.hours += rhs.hours;
   return temp;
 }

Собирањето е бинарна операција што значи дека има десен и лев операнд. Операторот собирање може да биде дефиниран и деклариран како метод на даден абстрактен објект. Во овој случај се подразбира(а и логично) е дека еден од операндите е примерок(инстанца) од абстрактниот објект(во овој пример абстрактниот објект е „Time“) во којшто е дефиниран преоптоварениот оператор. Во вака дефинираниот преоптоварен оператор lhs се пристапува директно.

 Time Time::operator+(const Time& rhs) const
 {
   Time temp = *this;  /* Copy 'this' which is not to be modified */
   temp.seconds += rhs.seconds;
   if (temp.seconds >= 60)
   {
     temp.seconds -= 60;
     temp.minutes++;
   }
   temp.minutes += rhs.minutes;
   if (temp.minutes >= 60)
   {
     temp.minutes -= 60;
     temp.hours++;
   }
   temp.hours += rhs.hours;
   return temp;
 }
  int main(int argc, char ** argv){
    Time fiveAM, myLunchTime; // декларација
    
    // внесување на податоците
    ...
    ...
    ...

    Time fiveHoursSinceLunch = fiveAM + myLunchTime; // myLunchTime се предава како аргумент на преклопениот оператор +
                                                     // повикот се извршува на следниот начин: fiveAM.operator+(myLunchTime)
                                                     // fiveAM како примерок(инстанца) ги содржи своите податоци, и соодветно
                                                     // може '''и''' се извршуваат сите потребни пресметки

                                                     // на крајот резулатот се враќа како примерок од видот Time(така е
                                                     // имплементирано), којшто
                                                     // * ако има дефинирано конструктор за копија, се повикува тој
                                                     // * ако нема, тогаш се извршува бинарно копирање

   Time fiveHoursSinceLunch2;
   fiveHoursSinceLunch2 = fiveAM + myLunchTime;      // се е исто, само на крајот ако е преоптоварен операторот за доделување(=)
                                                     // се повикува тој, во спротивен случај се врши бинарно копирање на резултатот
                                                     // вратен од fiveAM.operator+(myLunchTime)

Забелешка дека единичниот оператор дефиниран како метод на класата ќе прими не видлив аргумент. (само работи од this):

 bool Time::operator!() const
 {
   return ((hours == 0) && (minutes == 0) && (seconds == 0));
 }
 /* Исто така ова е пример како се злоупотребува преоптоварувањето на оператори, во овој код
    операторот негација враќа вистина ако е 0 часот, 0 минути и 0 секунди, во спротивен случај
    враќа невистина. Ова е спротивно на најголемиот дел од напишаниот код, којшто враќа невистина
    ако вредноста/групата од атрибути којашто се споредува е 0, а во сите спротивни случаи враќа
    вистина.
*/

Едно од најважните детали кога се имплементираат оператори за преоптеретување е фактот дека ниеден од најзастапените јазици за програмирање не нуди можност за промена на приоритетот на операторите за преоптоварување, водејќи до човечки грешки во фазата на проектирање, имплеметација, а и големи проблеми при процесот на дебагирање.

Каталог уреди

Класификација на некои општи програмски јазици во зависност од тоа дали нивните оператори може да се преоптоварат од програмерот, дали може да се дефинираат нови преоптоварени оператори или множеството на преоптоварени оператори е ограничено.

Оператори Не преоптоварени Преоптоварени
New definable
Limited set

Наводи уреди

  1. binary functions with a symbolic name can be called infix
  2. introduced in Fortran 90
  3. type classes instead of overloading
  4. operators use the same prefix syntax as functions