Přetížení operátora - Operator overloading
Polymorfismus |
---|
Ad hoc polymorfismus |
Parametrický polymorfismus |
Podtypování |
V počítačovém programování je přetížení operátorů , někdy nazývané operátor ad hoc polymorfismus , specifickým případem polymorfismu , kde různí operátoři mají různé implementace v závislosti na svých argumentech. Přetížení operátora je obecně definováno programovacím jazykem , programátorem nebo obojím.
Zdůvodnění
Přetížení operátoru je syntaktický cukr a používá se, protože umožňuje programování pomocí zápisu blíže k cílové doméně a umožňuje uživatelsky definovaným typům podobnou úroveň syntaktické podpory jako typy integrované do jazyka. Je to běžné například ve vědeckých počítačích, kde umožňuje manipulaci s výpočetními reprezentacemi matematických objektů se stejnou syntaxí jako na papíře.
Přetížení operátora nemění výrazovou sílu jazyka (s funkcemi), protože jej lze emulovat pomocí volání funkcí. Uvažujme například proměnné a
, b
a c
nějaké uživatelem definovaného typu, jako je například matice :
a + b * c
V jazyce, který podporuje přetížení operátora, as obvyklým předpokladem, že operátor '*' má vyšší prioritu než operátor '+', je to stručný způsob psaní:
Add(a, Multiply(b, c))
Bývalá syntaxe však odráží běžné matematické využití.
Příklady
V tomto případě je operátor sčítání přetížen, aby umožnil přidání na uživatelsky definovaný typ Time
v 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;
}
Sčítání je binární operace , což znamená, že má dva operandy . V C ++ jsou předávané argumenty operandy a temp
objekt je vrácená hodnota.
Operaci lze také definovat jako metodu třídy, nahrazenou lhs
skrytým this
argumentem; To však nutí levý operand být typu Time
:
// The "const" right before the opening curly brace means that |this| is not modified.
Time Time::operator+(const Time& rhs) const {
Time temp = *this; // |this| should not be modified, so make a copy.
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;
}
Všimněte si, že unární operátor definovaný jako metoda třídy neobdrží žádný zjevný argument (funguje pouze od this
):
bool Time::operator!() const {
return hours == 0 && minutes == 0 && seconds == 0;
}
Operátor menší než (<) je často přetížen, aby seřadil strukturu nebo třídu:
class Pair {
public:
bool operator<(const Pair& p) const {
if (x_ == p.x_) {
return y_ < p.y_;
}
return x_ < p.x_;
}
private:
int x_;
int y_;
};
Stejně jako u předchozích příkladů se v posledním příkladu přetížení operátoru provádí v rámci třídy. V C ++ lze po přetížení operátoru méně než (<) použít k třídění některých tříd standardní třídicí funkce .
Kritika
Přetížení operátora bylo často kritizováno, protože umožňuje programátorům znovu přiřadit sémantiku operátorů v závislosti na typech jejich operandů. Například použití <<
operátoru v C ++ posune bity v proměnné vlevo o bity, pokud a jsou celočíselného typu, ale pokud je výstupním proudem, výše uvedený kód se pokusí zapsat a do proudu. Protože přetížení operátorem umožňuje původnímu programátorovi změnit obvyklou sémantiku operátora a zaskočit všechny následné programátory, je považováno za vhodné používat přetížení operátora opatrně (tvůrci Javy se rozhodli tuto funkci nepoužívat, i když ne nutně z tohoto důvodu).
a << b
a
b
a
b
a
b
Další, jemnější problém operátorů je, že určitá pravidla z matematiky lze nesprávně očekávat nebo neúmyslně předpokládat. Například komutativita + (tj. Že a + b == b + a
) neplatí vždy; příkladem toho je situace, kdy jsou operandy řetězce, protože + je běžně přetíženo, aby provedlo zřetězení řetězců (tj. "bird" + "song"
výnosů "birdsong"
, zatímco "song" + "bird"
výnosů "songbird"
). Typický protiklad tohoto argumentu pochází přímo z matematiky: Zatímco + je komutativní na celá čísla (a obecně jakékoli komplexní číslo), není komutativní pro jiné „typy“ proměnných. V praxi + ani není vždy asociativní , například s hodnotami s plovoucí desetinnou čárkou kvůli chybám zaokrouhlení. Jiný příklad: V matematice je násobení komutativní pro reálná a komplexní čísla, ale není komutativní v maticovém násobení .
Katalog
Klasifikace některých běžných programovacích jazyků se provádí podle toho, zda jsou jejich operátory přetížitelné programátorem a zda jsou operátoři omezeni na předdefinovanou sadu.
Operátoři | Není přetížitelný | Přetížitelný |
---|---|---|
Nové definovatelné | ||
Omezená sada |
Časová osa přetížení operátora
60. léta 20. století
Specifikace ALGOL 68 umožňovala přetížení operátora.
Výpis ze specifikace jazyka ALGOL 68 (strana 177), kde jsou definovány přetížené operátory ¬, =, ≠ a abs :
10.2.2. Operations on Boolean Operands a) op ∨ = (bool a, b) bool:( a | true | b ); b) op ∧ = (bool a, b) bool: ( a | b | false ); c) op ¬ = (bool a) bool: ( a | false | true ); d) op = = (bool a, b) bool:( a∧b ) ∨ ( ¬b∧¬a ); e) op ≠ = (bool a, b) bool: ¬(a=b); f) op abs = (bool a)int: ( a | 1 | 0 );
Všimněte si, že k přetížení operátora není potřeba žádná zvláštní deklarace a programátor může vytvářet nové operátory.
80. léta 20. století
Ada podporuje přetížení operátorů od svého vzniku, a to vydáním jazykového standardu Ada 83. Jazykoví designéři se však rozhodli vyloučit definici nových operátorů. Přetíženy mohou být pouze existující operátory v jazyce, a to definováním nových funkcí pomocí identifikátorů jako „+“, „*“, „&“ atd. Následné revize jazyka (v letech 1995 a 2005) zachovávají omezení přetížení existujících operátorů .
V C ++ je přetížení operátora jemnější než v ALGOL 68 .
90. léta 20. století
Návrháři jazyka Java ve společnosti Sun Microsystems se rozhodli přetížení vynechat.
Ruby umožňuje přetížení operátora jako syntaktický cukr pro volání jednoduchých metod.
Lua umožňuje přetížení operátora jako syntaktický cukr pro volání metod s přidanou funkcí, že pokud první operand nedefinuje tohoto operátora, bude použita metoda pro druhý operand.
2000s
Microsoft přidal přetížení operátora do C# v roce 2001 a do Visual Basic .NET v roce 2003.
Scala považuje všechny operátory za metody a umožňuje tak přetížení operátora proxy.
V Raku je definice všech operátorů delegována na lexikální funkce, a tak lze pomocí definic funkcí přetížit operátory nebo přidat nové operátory. Například funkce definovaná ve zdroji Rakudo pro inkrementaci objektu Date pomocí „+“ je:
multi infix:<+>(Date:D $d, Int:D $x) {
Date.new-from-daycount($d.daycount + $x)
}
Vzhledem k tomu, „multi“ byl používán, funkce budou přidány do seznamu multidispatch kandidátů, a „+“ je přetížen pouze pro případ, kdy jsou splněny typu omezení v podpisu funkce. Zatímco kapacita pro přetížení zahrnuje + , * , > = , postfix a výraz i atd., Umožňuje také přetížení různých operátorů složených závorek: " [ x, y ] ", "x [ y ] ", "x { y } "a" x ( y ) ".
Kotlin podporuje přetížení operátora od jeho vytvoření.
Viz také
- Přetížení funkce
- Polymorfismus (počítačová věda)
- Podprogram
- Operátor (programování)
- Operátory v C a C ++
- Metoda mutátora
- Indexer (programování)
- Vlastnost (programování)