nisfarm.ru

Přetížení operátora v C ++: základy, příklady

Ve všech vědách existují standardní názvy, které usnadňují porozumění myšlenek. Například v matematice je to násobení, dělení, sčítání a další symbolická notace. Výraz (x + y * z) je mnohem snazší pochopit než "násobit y, c, z a přidat do x". Představte si, že před šestnáctým stoletím neměla matematika žádné symbolické označení, všechny výrazy byly psány slovně, jako by to byl umělecký text s popisem. A obvyklá notace pro operace se objevila později. Význam krátkého charakteru je těžké přeceňovat. Na základě těchto úvah byly do programovacích jazyků přidány přetížení operátorů. Zvažte příklad.

Příklad přetížení obsluhy

Téměř jako každý jazyk podporuje C ++ mnoho operátorů, kteří pracují s datovými typy zabudovanými do jazykového standardu. Většina programů však používá vlastní typy k řešení určitých úkolů. Například složitá matematika nebo maticová algebra jsou realizovány v programu díky reprezentaci komplexních čísel nebo matic ve formě uživatelsky definovaných typů C ++. Vestavěné operátory neví, jak distribuovat svou práci a provádět potřebné procedury v učebnách uživatelů, ačkoli se zdá, že se mohou zdát. Proto k přidání matic například obvykle vzniká samostatná funkce. Je zřejmé, že volání sum_matrix (A, B) v kódu bude méně jasné než výraz A + B.

Reprezentace komplexního čísla

Zvažte přibližnou třídu komplexních čísel:

// komplexní číslo reprezentován jako dvojice plovoucích tochkoy.class komplex {double re, im-veřejnost: komplex (double r, dvojité i): Re (R), im (i) {} // konstruktorcomplex operátor + (komplex) - // přetížení operátor slozheniyacomplex * (komplex) - // přetížení násobení} -void hlavní () {komplex a {1, 2}, b {3, 4}, C {0, 0} -C = a + bc = a.operator + (b) - //// funkce operátor může být způsobena jakoukoli funkci, vstup je ekvivalentní + bc = a * b + komplexu (1, 3) - // provést normální pravidla přednosti sčítání a násobení operace}

Podobně můžete například přenášet I / O operátory v jazyce C ++ a přizpůsobit je výstupům tak komplexních struktur jako matric.

Provozovatelé jsou k dispozici pro přetížení

Kompletní seznam všech operátorů, pro které můžete použít mechanismus přetížení:

+

;

* * *

/

%

^

| |. |

~

!

=

<




+=

-=

* =

/ =

% =

^ =

=

| =

<<

> =

<<=

==

!=

<=

=

||

++

-;

-> *

,

->

[]

()

nové

nový []

vymazat

smazat []

Jak vidíte z tabulky, přetížení je přijatelné pro většinu operátorů jazyků. Provozovatel nemůže být přetížen. To se provádí pouze pro pohodlí. Proto není například přetížení operátora v jazyce Java k dispozici. A teď o dalším důležitém okamžiku.

Operátoři nejsou přetíženi

  • Rozlišení rozsahu je "::";
  • Volba člena je ".";
  • Výběr člena prostřednictvím ukazatele člena je ". *";
  • Terénní podmíněný operátor je "?:";
  • Velikost operátora;
  • Operátor typeid.

Správným operantem těchto operátorů je jméno, ne hodnota. Proto vyřešení jejich přetížení by mohlo vést k napsání mnoha nejednoznačných konstrukcí a značně by komplikovalo život programátorů. Ačkoli existuje mnoho programovacích jazyků, ve kterých mohou všichni operátoři přetížit - například přetížení operátorů Pythonu.

Omezení

Omezení přetížení operátora:

Schéma operátorů k přetížení
  • Nemůžete změnit binární operátor na unární operátor a naopak, stejně jako nemůžete přidat třetí operandu.
  • Nelze vytvořit nové operátory kromě těch, které jsou k dispozici. Toto omezení odstraňuje mnoho nejednoznačností. Je-li potřeba nového operátora, můžete pro tento účel použít funkci, která provede požadovanou akci.
  • Funkce operátora může být buď členem třídy, nebo má alespoň jeden argument uživatele definovaného typu. Výjimkou jsou noví operátoři a operátoři mazání. Toto pravidlo zakazuje změnu významu výrazů v případě, že neobsahují typy objektů definované uživatelem. Zejména nelze vytvořit funkci operátora, která funguje výhradně s ukazateli nebo způsobí, že operátor přidání pracuje jako násobení. Výjimkou jsou operátory "=", "" a "," pro objekty třídy.
  • Funkce operátora s prvním členem patřícím k jednomu z vestavěných datových typů jazyka C ++ nemůže být členem třídy.
  • Název jakékoliv operátorské funkce začíná operátorem klíčového slova, následovaným symbolickým označením samotného operátora.
  • Vestavěné operátory jsou definovány tak, že mezi nimi existuje spojení. Například následující operátory jsou vzájemně ekvivalentní: ++ x- x + = 1 - x = x + 1. Po nové definici se vztah mezi nimi nezachová. Zachování jejich týmové práce tímto způsobem s novými typy programátorů se bude muset starat samostatně.
  • Kompilátor neví, jak myslet. Výrazy z + 5 a 5 + z (kde z je složité číslo) bude s překladačem zacházeno odlišně. První je "složité + číslo" a druhé je "číslo + složité". Proto musíte pro každý výraz definovat svůj vlastní operátor.
  • Při hledání definice operátora kompilátor nedává přednost členským funkcím třídy ani pomocným funkcím definovaným mimo třídu. Pro překladatele jsou stejné.

Interpretace binárních a unárních operátorů.

Binární operace

Binární operátor je definován jako členová funkce s jednou proměnnou nebo jako funkce se dvěma proměnnými. Pro každý binární operátor @ platí následující konstrukce ve výrazu a @ b, @:

operátor @ (b) nebo operátor @ (a, b).

Zvažte příklad třídy složitých čísel definici operací jako členů třídy a pomocných.

třídní komplex {double re, im-public: komplex operátor + = (komplex z) -komplex operátor * = (komplex z) -} - // pomocné funkce komplexní operátor + (komplex z1, komplex z2) -komplexní operátor + (komplex z, dvojité a) -

Který z provozovatelů bude vybrán a zda bude vybrán vůbec, je určen interními mechanismy jazyka, které budou popsány níže. Obvykle se to děje podle přizpůsobení typu.

Volba, popsat funkci člena třídy nebo mimo ni je obecně otázkou chuti. Ve výše uvedeném příkladu, princip volby je následující: v případě, že operace modifikuje levý operand (například A + = b), a pak jej zaznamenat do třídy a použít měnitelným převodem na, k jeho okamžitému Změny- pokud operace nic nemění a jen vrací novou hodnotu ( například a + b) přesahuje definici třídy.

Unární a binární operace

Určení přetížení unárních operátorů v jazyce C ++ se děje podobným způsobem s tím rozdílem, že jsou rozděleny do dvou typů:

  • operátor prefixu, umístěný před operandem, - @a, například ++ i. o je definován jako a.operator @ () nebo operátor @ (aa);
  • operátor postfixu umístěný za operandem - b @, například i ++. o je definován jako b.operator @ (int) nebo operátor @ (b, int)

Stejně jako u binárních operátorů pro případ, kdy je příkaz operátora v třídě i mimo třídu, bude volba provedena mechanismy C ++.

Pravidla výběru operátora

Typy operátorů C ++

Nechte binární operátor @ aplikovat na objekty x z třídy X a y ze třídy Y. Pravidla pro vyřešení x @ y budou následující:

  1. pokud X je třída, podívejte se uvnitř na definici operátora @ jako člena X nebo základní třídy X;
  2. zobrazit kontext, ve kterém je umístěn výraz x @ y;
  3. pokud X odkazuje na jmenný prostor N, podívejte se na prohlášení operátora v N;
  4. pokud Y odkazuje na jmenný prostor M, vyhledejte příkaz operátora v M.

V případě, že bylo nalezeno několik oznámení operátora operátora @ 1-4, volba bude provedena podle pravidel pro řešení přetížených funkcí.

Hledání jednorázových operátorů je přesně stejné.

Vyjasnění definice složitých

Teď budeme sestavit třídu komplexních čísel podrobněji, abychom demonstrovali řadu předtím vyjádřených pravidel.

třídní komplex {double re, im-public: komplex operátor + = (komplex z) {// pracuje s výrazy formuláře z1 + = z2re + = z.re-im + = z.im-return * this-} komplex Operátor + = (double a) {// pracuje s výrazy formy Z1 + = 5-re + = a zpětný * tohle} komplex (): Re (0), im (0) {} // výchozí konstruktor pro inicializaci . Tak, všechny komplexní čísla deklarované bude mít počáteční hodnoty (0, 0) (dvojitá R): re (r), im (0) {} // konstruktor umožňuje expresi formě komplexu z = 11- ekvivalentní záznam z = komplexní (11) -komplex (double r, dvojité i): Re (r), im (i) {} // konstruktor} -komplex operátor + (komplex z1, komplex z2) {// pracuje s výrazy formy Z1 + z2complex res = Z1 zpětné res + = z 2- // použití operátor definován jako členské funkce} komplex operátor + (komplex z, dvojitý a) {// rukojeť výrazy formy z + 2complex res = z zpětné res + = a-} komplex operátora + (double a, komplex z) {// zpracovává výrazy formy 7 + zcomplex res = z zpětné res + = a -} // hellip-

Jak můžete vidět z kódu, přetížení operátora má velmi složitý mechanismus, který může velmi růst. Takový podrobný přístup však umožňuje přetížení i pro velmi složité datové struktury. Například přetížení příkazů C ++ ve třídě šablon.

Takové vytváření funkcí pro každého a vše může být únavné a vést k chybám. Například pokud přidáte ke zváženým funkcím třetí typ, je třeba zvážit operace z důvodů kombinace tří typů. Je třeba napsat 3 funkce s jedním argumentem, 9 - s dvěma a 27 - se třemi. Proto v řadě případů může být realizace všech těchto funkcí a výrazné snížení jejich počtu dosaženo použitím konverzí typu.

Zvláštní operátoři

Operátor indexu "[]" musí být vždy definován jako člen třídy, protože snižuje chování objektu na matici. Argument indexování může být libovolného typu, který umožňuje vytvářet například asociativní pole.

Operátor pro volání funkce "()" lze považovat za binární operaci. Například v konstrukci výrazu (výraz list) je levý operand binární operace () výrazem a správný operand je seznam výrazů. Funkce operátora () () musí být členem třídy.

Operátor sekvence "," (čárka) je volán pro objekty, pokud vedle nich je čárka. Operátor se však nezúčastní na výčtu argumentů funkcí.

Operátor dereferencing "->" musí být také definován jako člen funkce. Ve smyslu může být definován jako unary operátor postfix. V takovém případě musí nutně vrátit buď odkaz nebo ukazatel, který umožňuje přístup k objektu.

Provozovatel přiřazení Je také definován pouze jako člen třídy vzhledem k jeho vztahu k levému operandu.

Operátoři přiřazení "=", adresy "" a sekvence "," musí být definovány ve veřejném bloku.

Výsledek

Přetížení operátoři pomáhají implementovat jeden z klíčových aspektů OOP o polymorfismu. Je však důležité si uvědomit, že přetížení není víc než jiný způsob volání funkcí. Úkolem přetížení operátorů je často zlepšit pochopení kódu, než zajistit výhry v některých otázkách.

Co je polymorfismus?

A to není všechno. Mělo by se také vzít v úvahu, že přetížení operátorů je složitým mechanismem se spoustou nástrah. Proto je velmi snadné udělat chybu. To je hlavní důvod, proč většina programátorů doporučuje, aby se zdržely používání přetížení operátora a uchýlila se k němu pouze jako poslední možnost a s plnou důvěrou ve své kroky.

Doporučení

C ++ Stvořitel Bjarne Stroustrup
  1. Proveďte přetížení operátora pouze k simulaci známého záznamu. Aby byl kód čitelnější. Pokud se kód stane složitější ve struktuře nebo čitelnosti, měli byste se vyhnout přetížení operátorů a používat funkce.
  2. U velkých operandů použijte argumenty s typem konstantních odkazů pro přenos, aby se ušetřilo místo.
  3. Optimalizujte návratové hodnoty.
  4. Nedotýkejte se kopírování, pokud je vhodná pro vaši třídu.
  5. Pokud kopírování ve výchozím nastavení nefunguje, změňte nebo výslovně zakázat kopírování.
  6. Nejlépe byste měli upřednostňovat funkce členů v případě nečlenských funkcí v případech, kdy funkce vyžadují přístup k zastupování třídy.
  7. Určete jmenný prostor a označte vztah funkcí k jejich třídě.
  8. Pro symetrické operátory použijte nečlenské funkce.
  9. Použijte operátor () pro indexy ve vícerozměrných polích.
  10. Buďte opatrní s implicitními konverzemi.
Sdílet na sociálních sítích:

Podobné
© 2021 nisfarm.ru