Направо към съдържанието

Предефиниране на оператор

от Уикипедия, свободната енциклопедия

В програмирането, предефинирането на оператор (на английски: operator overloading / ad hoc polymorphism) е специфичен случай на полиморфизъм, при който различните оператори имат различна имплементация зависеща от аргументите ѝ. Предефинирането на оператор се определя от програмния език, програмиста или от двете.

Мотивация[редактиране | редактиране на кода]

При предефинирането на оператори се използва синтаксис, който прави програмния език по-лесен за четене и разбиране или това е така наречената синтактична захар. Операторните декларации са разширение на вече съществуващите в езика оператори върху новосъздадени класове, което позволява на програмиста да използва синтаксис близък до този, който вече е вграден в програмния език.

Често срещано е изчисленията, които се правят в програмата да имат сходен синтаксис до този, който се прави на лист. Например, нека A, B, C са променливи от тип Matrix (матрица):

 A + B * C

Но в език, който не поддържа предефиниране на оператори това ще има вида:

 add(A, multiply(B, C))

Примери[редактиране | редактиране на кода]

В този пример, операторът са събиране е предефиниран за да позволи събиране на дефинирани от потребителя типове „Time“ (C++):

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

Операторът за събиране е бинарен, което означава, че използва два операнда. Операцията може да бъде дефинирана и като метод в клас, като единия аргумернт lhs се замести с this , но това означава, че и левият операнд трябва да бъде от тип Time:

Time Time::operator+(const Time& rhs) const /* const means that 'this' is not to be modified */
{
    Time temp = *this; /* Copy 'this' which is not to be modified */
    temp.seconds += rhs.seconds;
    temp.minutes += temp.seconds / 60;
    temp.seconds %= 60;
    temp.minutes += rhs.minutes;
    temp.hours += temp.minutes / 60;
    temp.minutes %= 60;
    temp.hours += rhs.hours;
    return temp;
}

Унарните оператори, дефинирани в метод на клас могат да не приемат видими аргументи (работят само с this):

bool Time::operator!() const
{
    return ((hours == 0) && (minutes == 0) && (seconds == 0));
}

Операторът за сравнение „по-малко“ (<) често се предефинира за сортиране на структура или клас:

class pair
{
	public:
	int x,y;
	bool operator < (const pair& p) const
	{
		if(x==p.x) return y<p.y;
		return x<p.x;
	}
};

В последния пример, предефинирането на оператора за сравнение „по-малко“ (<) е в конкретен клас, което означава, че могат да се прилагат сортиращи функции с обекти от този клас.

Критика[редактиране | редактиране на кода]

Предефинирането на оператори често бива критикувано[1], тъй като позволява на програмиста да дава различен смисъл на операторите в зависимост от случаите. Например в C++ оператора <<:

 а << 1

Ако приемем, че a е реално число, то << ще измести битовете му наляво веднъж, но ако a е поток, то << ще изпише "1" на потока. Това може да доведе до объркване и се счита за добра практика, предефинирането на оператори да се използва внимателно.

Друг проблем, който възниква е, че някои правила от математика са грешно използвани или приети на сляпо. Пример може да се даде с разместително свойство на събирането – нека a и b са променливи. Ако те са числа, то при тях важи, че a + b == b + a, но ако а = "Some" и b = "String" (a + b == „SomeString“ и b + a == „StringSome“), то a + b != b + a. На практика, + не е асоциативен до при числата с плаващата запетая, поради грешки при закръглянето. Подобен пример може да се даде и с умножението, което също има разместително свойство, що се отнася до реални числа, но не и когато става въпрос за умножение на матрици.

Класификация[редактиране | редактиране на кода]

Оператори Непредефинируеми Предефинируеми
Ново дефинирани
Ограничени

Вижте също[редактиране | редактиране на кода]

Източници[редактиране | редактиране на кода]

  1. Issues in Overloading
  2. Why does Go not support overloading of methods and operators? // Посетен на 4 септември 2011.
  3. Operator Overloading, Delphi Manual // Посетен на декември 2014.
  4. Implementing Operators for Your Class // Посетен на октомври 2013.
  5. Operator Overloading, Free Pascal Manual // Посетен на декември 2014.