Preťaženie operátorov v jazyku C ++: základy, príklady

V akejkoľvek vede, existujú štandardné notácie, ktoré uľahčujú pochopenie myšlienok. Napríklad v matematike je násobenie, delenie, pridanie a iná symbolická notácia. Výraz (x + y * z) je oveľa ľahšie pochopiteľný ako "násobenie y, z a pridanie do x". Predstavte si, že až do XVI. Storočia matematika nemala symbolickú notáciu, všetky výrazy boli napísané slovne, akoby to bol umelecký text s opisom. A zvyčajné príznaky operácií pre nás sa objavili neskôr. Je ťažké preceňovať význam krátkeho záznamu o znakoch. Na základe týchto úvah boli programovacie jazyky pridané k preťaženiu operátorov. Zoberme si príklad.


Príklad preťaženia operátorom

Takmer akýkoľvek jazyk podporuje C ++ množstvo operátorov pracujúcich s dátovými typmi zabudovanými do štandardného jazyka. Ale väčšina programov používa na riešenie určitých úloh špeciálne typy. Napríklad komplexná matematika alebo maticová algebra je implementovaná v programe reprezentovaním zložitých čísel alebo matíc v typoch C ++. Vstavané operátori nie sú schopní distribuovať svoju prácu a vykonať potrebné postupy nad určitými triedami, akokoľvek zrejmé sa môžu zdajú. Preto je napríklad pri pridávaní matríc obvykle vytvorená samostatná funkcia. Je zrejmé, že volanie sum_matrix (A, B) v kóde bude mať menej jasný charakter ako výraz A + B.
Zvážte približnú triedu zložitých čísel:

//Predstavte si komplexné číslo vo forme dvojice čísel spohyblivé body.
komplex tried {{12} double re, im;
verejné:
komplex (double r, dvojité i): Re (r), im (i) {} //konštruktor
komplex operátor + (komplex); zostava preťaženia
komplexný operátor * (komplex); //preťaženie násobenia
};

void hlavná () {
komplexná {1 2}, b {3}}, c {0}};
c = a + b;
c = a.operátor + (b); ////funkcia operátora môže byť nazvaná ľubovoľná funkcia, táto položka je ekvivalentná k + b
c = a * b + komplexu (1 3); //vykonáva zvyčajné pravidlá prioritných operácií sčítanie a násobenie
}

Rovnako možno vykonať, ako je napríklad operátor preťaženie /O v jazyku C ++ a prispôsobiť je pre zobrazenie také zložité štruktúry ako šablóny.

Prevádzkovatelia sú k dispozícii k preťaženiu

Plný zoznam všetky subjekty, ktoré možno použiť mechanizmus preťaženia

62]

nový

+

-

*

/

%

^

~

!

=

/p>

>

+ =

- =

* =

/=

% =

a

| =

=

=

==

! =

> =

|

++

,

->

zrušiť

Ako je zrejmé z tabuľky, preťaženie je pre väčšinu operátorov jazykov prípustné. Nie je potrebné preťaženie operátora. Toto sa vykonáva výhradne pre pohodlie. Preto napríklad neexistuje preťaženie operátorov v jazyku Java. A teraz o tak dôležitom momente.

Prevádzkovatelia, ktorých preťaženie je zakázané

  • Povolenie na viditeľnosť - «::»;
  • Voľba člena je ".";
  • Výber člena prostredníctvom ukazovateľa členovi - ". *";
  • Tretí podmienený operátor - «?:»;
  • veľkosť operátora;
  • Typ operátora.

Správnym operandom dát operátorov je meno, nie hodnota. Preto povolenie na ich preťaženie by mohlo viesť k písaniu mnohých nejednoznačných návrhov a značne by komplikovalo život programátorov. Aj keď existuje veľa programovacích jazykov, ktoré umožňujú preťaženie všetkých operátorov - napríklad preťaženie operátorov Pythonu.


Obmedzenie operátor preťaženie

  • Nemôžete zmeniť binárny operátor na unary a naopak, pretože nemôžete pridať tretí operand.
  • Nemôžete vytvoriť iné operátory, ako sú tie, ktoré sú. Toto obmedzeniepodporuje odstránenie mnohých nejasností. Ak je potrebný nový operátor, môžete použiť funkciu, ktorá na tieto účely vykoná požadovanú akciu.
  • Funkcia operátora môže byť buď členom triedy, alebo má aspoň jeden typový argument. Výnimkou sú noví operátori a operátori odstránení. Toto pravidlo zakazuje zmenu významu výrazov, ak neobsahujú užívateľom definované typy objektov. Najmä nemôžete vytvoriť funkciu operátora, ktorá by fungovala iba s ukazovateľmi alebo nútiť operátora, aby pracoval ako násobenie. Výnimkou sú operátori "=", "& amp;" a "," pre triedy objektov.
  • Operátor s prvým termínom, ktorý patrí do jedného z vstavaných typov údajov v jazyku C ++, nemôže byť členom tejto triedy.
  • Názov akejkoľvek funkcie operátora začína operátorom kľúčového slova, za ktorým nasleduje symbolické označenie samotného operátora.
  • Vstavané operátory sú definované takým spôsobom, že medzi nimi existuje spojenie. Napríklad, nasledujúce operátory sú navzájom ekvivalentné: ++ x; x + = 1; x = x + 1. Po novom definovaní sa spojenie medzi nimi nezachová. O udržiavaní ich práce spoločne podobne ako nové typy programátorov sa budú musieť starať o seba.
  • Kompilátor nemôže premýšľať. Výrazy z + 5 a 5 + z (kde z - zložité číslo) bude kompilátor zvažovať rôznymi spôsobmi. Prvý z nich je "zložité + číslo" a druhý je "číslo + zložité". Preto pre každý výraz musíte definovať vlastné vyhlásenie o pridanie.
  • Pri hľadaní definície operátora kompilátor neuprednostňuje žiadne funkcie členov triedy ani pomocné funkcie,ktoré sú definované mimo triedy. Pre zostavovateľa sú rovnaké.

Interpretácie binárnych a unárnych operátorov.

binárne operátor je definovaný ako člen funkcia jednej premennej alebo funkcie dvoch premenných. Pre každý binárne vyjadrenie obsluhy @ s @ b @ len štruktúr:


teplote nižšej ako script type = "text /javascript" & gt;
var blockSettings3 = {blockId: "R-A-70350-3", renderTo "yandex_rtb_R-A-70350-3", async:! 0};

, ak (document.cookie.indexOf ("abmatch =") väčšie alebo rovné 0) {
blockSettings3 = {blockId: "RA-70350-3", renderTo "yandex_rtb_R-A-70350- 3 ", stav: 70350async: 0};
}

! Funkcie (a, b, c, d, e) {a [c] = a [c] || [], sa [C] .push (funkcia () {Ya .Context.AdvManager.render (blockSettings3)}), e = b.getElementsByTagName ("scenár") , d = b.createElement ("scenár"), d.type = "text /javascript", d.src = "//an.yandex.ru/system/context.js",d.async=!0e.parentNode.insertBefore(d,e)}(this,this.document,"yandexContextAsyncCallbacks");

a.operator @ (b), alebo prevádzkovateľ '(a, b).

Uvažujme príklad definíciu triedy komplexných čísel operácií ako členovia triedy a pomocné látky.

komplex tried {{174} double re, im;
verejné:
komplexné & operátor + = (komplex z);
komplexu; operátor * = (komplex z);
};
//pomocné funkcie
komplexný operátor + (komplex z1 komplex z2);
komplexný operátor + (komplex z, dvojité a);

, ktoré operátorov bude vybraný a byť volený všeobecne určený vnútorných mechanizmov jazyka, ktoré budú popísané nižšie. Typicky sa to deje podľa typov.

​​

Vyberte opísať funkciu ako člen triedy alebo mimo nej - je, všeobecne, chuť. Vo vyššie uvedenom príklade je princíp výberu bola nasledujúca: v prípade, že operácia zmení ľavý operand (napríklad A + = b), a potom ho zaznamenať v triede a pomocou meniteľným prevodom pri, pre jeho bezprostredné zmeny; ak operácia nie je ničmodifikuje a jednoducho vracia novú hodnotu (napríklad a + b) - za definíciu triedy.

Definícia preťaženia unárnych operátorov v C ++ sa vyskytuje rovnakým spôsobom s tým rozdielom, že sú rozdelené do dvoch typov:

  • prefix operátor, ktorý sa nachádza na operande, - napríklad @ i ++. o Definovaný ako a.operátor @ () alebo operátor @ (aa);
  • operátor postfix, umiestnený za operandom, - b @, napríklad i ++. o Definovaný ako b.operator @ (int) alebo operátor @ (b, int)

Rovnako ako v prípade binárnych operátorov, v prípade, že vyhlásenie operátora je v triede aj mimo triedy, výber bude vykonaný mechanizmami C ++.

Pravidlá výberu operátora

Nech sa binárny operátor @ aplikuje na objekty x triedy X a y triedy Y. Pravidlá pre rozlíšenie x @ y budú nasledovné:

  1. ak je X trieda, pozrite sa do nej definícia operátora @ ako výraz X alebo základnej triedy X;
  2. na zobrazenie kontextu, v ktorom sa nachádza výraz x @ y;
  3. ak X patrí do menného priestoru N, pozrite sa na vyhlásenie operátora N;
  4. Ak Y patrí do menného priestoru M, pozrite sa na vyhlásenie operátora M.

Ak sa v zázname 1 až 4 našlo niekoľko vyhlásení prevádzkovateľa operátora @, voľba sa vykoná podľa pravidiel povolenia preťažených funkcií.

Vyhľadávanie unároch operátorov sa uskutočňuje presne rovnakým spôsobom.

Vylepšite definíciu komplexu triedy

Teraz budeme vytvoriť triedu komplexných čísel podrobnejším spôsobompreukázať množstvo predtým ohlásených pravidiel.

komplex triedy {
double re, im;
verejné:
komplexné & operátor + = (komplex z) {//pracuje s výrazmi formulára z1 + = z2
re + = z.re;
im + = z.im;
návrat * to;
}
komplexný & operátor + = (double a) {//pracuje s výrazmi formulára z1 + = 5;
re + = a;
návrat * to;
}
komplex (): re

, im

{} //konštruktor pre inicializáciu štandardne. Preto všetky deklarované celé čísla majú počiatočné hodnoty (0 0)
komplexné (dvojité r): re (r), im

{} //konštruktér umožňuje vyjadrenie formy komplexu z = 11; zodpovedá záznamu z = komplex
;
komplex (dvojitý r, dvojitý i): re (r), im (i) {} //konštruktor
};
zložitý operátor + (komplex z1 komplex z2) {//funguje s výrazmi z1 z2 +2 zložitého komplexu res = z1;
návrat res + = z2; //používa operátor definovaný ako členská funkcia
}
zložitý operátor + (komplex z, dvojitý a) {//spracováva výrazy formulára z + 2
komplex res = z;
návrat res + = a;
}
komplexný operátor + (dvojité a, zložité z) {//spracováva výrazy formulára 7 + z
komplex res = z;
vrátiť res + = a;
236 239 238 Ako je zrejmé z kódu, preťaženie operátorov má pomerne komplikovaný mechanizmus, ktorý môže veľmi rásť. Takýto podrobný prístup vám však umožňuje preťaženie aj pri veľmi zložitých dátových štruktúrach. Napríklad preťaženie operátorov C ++ v triede šablón. Takéto vytvorenie funkcií pre každého a všetko môže byť únavné a viesť k chybám. Napríklad, ak pridáte tretí typ zvažovaných funkcií, potom budete musieť zvážiť operácie z dôvodu kombinácie troch typov. Budeme musieť napísať 3 funkcie s jedným argumentom, 9 - s dvomi a 27 - s tromi. Preto v niektorých prípadoch, vykonávanie všetkých týchto funkcií a ich významné zníženiemnožstvám je možné dosiahnuť použitím konverzie typov.

Špeciálni operátori

Operátor indexovania "[]" by mal byť vždy definovaný ako člen triedy, pretože znižuje správanie objektu na pole. V tomto prípade argument indexovania môže byť akéhokoľvek typu, ktorý umožňuje napríklad vytvorenie asociatívnych polí. Operátor hovoru funkcie (() môže byť považovaný za binárnu operáciu. Napríklad v konštrukcii "výraz (zoznam výrazov)" bude ľavý operand binárnej operácie () "výraz" a pravý je zoznam výrazov. Funkcia operátora () () musí byť členom triedy. Operátor sekvencie "," (čiarka) sa volá pre objekty, ak je vedľa nich čiarka. Operátor sa však nezúčastňuje na prenose funkčných argumentov. Operátor pomenovania "->" musí byť tiež definovaný ako člen funkcie. Vo svojom obsahu môže byť definovaný ako unary operátor postfix. Zároveň musí nevyhnutne vrátiť odkaz alebo ukazovateľ, ktorý umožňuje prístup k objektu. Operátor priradenia je tiež definovaný len ako člen triedy kvôli jeho spojeniu s ľavým operandom. Operátori priradenia «=», adresy «& amp;;» a sekvencia «,» musia byť definované vo verejnom bloku.

Výsledok

Preťaženie prevádzkovateľa pomáha realizovať jeden z kľúčových aspektov PLO na polymorfizme. Je však dôležité pochopiť, že preťaženie nie je nič iné, než iný spôsob volania funkcií. Úlohou preťaženia operátorov je často zlepšiť porozumenie kódu, ako zabezpečiť víťazstvo v akýchkoľvek otázkach.
A to nie je všetko. Tiež je potrebné mať na pamäti, že preťaženie operátorov je zložitý mechanizmus s množstvom úskalí. Preto je veľmi jednoduché urobiť chybu. To je hlavný dôvod, prečo väčšina programátorov odporúča, aby sa zdržali používania preťaženia prevádzkovateľa a využili ho len v extrémnych prípadoch as plnou dôverou vo svoje kroky.

Odporúčania

  • Vykonajte preťaženie operátora iba na simuláciu bežného záznamu. Aby bolo možné čítať kód. Ak sa kód stane zložitejším z hľadiska štruktúry alebo čitateľnosti, mali by ste upustiť od preťaženia operátorov a používať funkcie.
  • Pre veľké operandy, aby sa šetrilo miesto, použite argumenty na písanie s konštantnými odkazmi na prenos.
  • Optimalizujte návratové hodnoty.
  • Nedotýkajte sa kopírovania, ak je vhodná pre vašu triedu.
  • Ak predvolená kópia nie je vhodná, upravte alebo explicitne zakážte kopírovanie.
  • Funkcie členstva by sa mali uprednostňovať pred nečlenskými funkciami v prípadoch, keď funkcie vyžadujú prístup k reprezentácii triedy.
  • Označte priestor názvov a uveďte vzťah medzi funkciami triedy.
  • Použite nečlenské funkcie pre symetrické operátory.
  • Použite operátor () pre indexy v multidimenzionálnych poliach.
  • Použite opatrnosť s implicitnými transformáciami.
  • Súvisiace publikácie