OqPoWah.com

Preobremenitev operaterja v C ++: osnove, primeri

V vsaki znanosti obstajajo standardne oznake, ki olajšajo razumevanje idej. Na primer, v matematiki je množenje, delitev, dodajanje in druga simbolična notacija. Izraz (x + y * z) je veliko lažje razumeti kot "pomnoži y, c, z in dodati v x". Predstavljajte si, da pred šestnajstim stoletjem matematika ni imela simboličnih imen, vsi izrazi so bili ustno napisani kot umetniško besedilo z opisom. Običajna notacija za operacije se je pojavila pozneje. Pomen kratkega zapisa znakov je težko preceniti. Na podlagi teh premislekov so prevajalske preobremenitve dodane programskim jezikom. Razmislite o primeru.

Primer preobremenitve operaterja

Skoraj kot vsak jezik, C + + podpira številne operaterje, ki delujejo s tipi podatkov, vgrajenimi v jezikovni standard. Toda večina programov uporablja vrste po meri za reševanje določenih nalog. Na primer, kompleksna matematika ali matrična algebra se izvajajo v programu zaradi predstavitve kompleksnih števil ali matrik v obliki uporabniško določenih vrst C + +. Vgrajeni operaterji ne vedo, kako distribuirati svoje delo in izvajati potrebne postopke za uporabniške razrede, vendar so očitno, da se morda zdijo. Zato je za dodajanje matrike na primer ponavadi ustvarjena ločena funkcija. Očitno je, da je klic v sum_matrix (A, B) v kodi manj jasen kot izraz A + B.

Zastopanje kompleksne številke

Razmislite o približnem razredu zapletenih številk:

// kompleksno število zastopana kot par plavajočih tochkoy.class kompleksu {dvojna ponovno, im-javno: kompleks (dvojna r, dvojna i): re (r), im (i) {} // konstruktorcomplex operaterja + (kompleks) - // preobremenitev slozheniyacomplex operater * (kompleks) - // preobremenitvijo množenje} -void glavni () {kompleks {1, 2}, b {3, 4}, c {0, 0} -C = a + bc = a.operator + (b) - //// funkcijo operater se lahko vsaka funkcija povzročene vnos enakovredna + bc = A * b + kompleksa (1, 3) - // opravlja običajne prednostna pravila seštevanja in množenja operacij}

Podobno lahko na primer preobremenite I / O operaterje v C + + in jih prilagodite izhodnim kompleksnim strukturam, kot so matrike.

Operaterji so na voljo za preobremenitev

Popoln seznam vseh operaterjev, za katere lahko uporabite mehanizem preobremenitve:

+

;

*

/

%

^

| |

~

!

=

<

+=

-=

* =

/ =

% =

^ =

=

| =

<<

> =

<<=

==

!=

<=

=

||

++




-;

-> *

,

->

[]

()

novo

novo []

izbrisati

izbriši []

Kot vidite iz tabele, je preobremenitev sprejemljiva za večino jezikovnih operaterjev. Operaterja ni mogoče preobremeniti. To se naredi izključno za udobje. Zato preobremenitev operaterja v Java, na primer, ni na voljo. In zdaj o naslednjem pomembnem trenutku.

Operaterji niso preobremenjeni

  • Razrešitev obsega je "::";
  • Izbira člana je ".";
  • Izbira člana prek kazalca člana je ". *";
  • Trojni pogojni operater je "?:";
  • Velikost operaterja;
  • Tipid operater.

Pravi operand teh operaterjev je ime in ne vrednost. Zato bi reševanje njihove preobremenitve lahko pripeljalo do pisanja številnih dvoumnih konstrukcij in bi veliko otežilo življenje programerjev. Čeprav obstaja veliko programskih jezikov, v katerih lahko vsi operaterji preobremenijo - na primer preobremenitev operaterjev Python.

Omejitve

Omejitve preobremenitve operaterja:

Grafikon operaterjev, ki so na voljo za preobremenitev
  • Binarnega operaterja ne morete spremeniti na operaterja unary in obratno, tako kot ne morete dodati tretjega operanda.
  • Ne morete ustvariti novih operaterjev, razen tistih, ki so na voljo. Ta omejitev odpravlja številne dvoumnosti. Če potrebujete novega operaterja, lahko za ta namen uporabite funkcijo, ki bo izvedla zahtevano dejanje.
  • Funkcija operaterja je lahko bodisi član razreda bodisi vsaj en argument uporabniško določene vrste. Izjeme so novi operaterji in brisanje. To pravilo prepoveduje spreminjanje pomena izrazov v primeru, da ne vsebujejo tipov objektov, ki jih določi uporabnik. Zlasti ne morete ustvariti funkcije operaterja, ki deluje izključno s kazalci ali povzroči, da operater z dodatkom deluje kot množenje. Izjema so operatorji "=", "" in "," za predmete razreda.
  • Funkcija operaterja s prvim članom, ki pripada eni od vgrajenih podatkovnih tipov jezika C ++, ne more biti član razreda.
  • Ime katere koli operativne funkcije se začne z operaterjem ključnih besed, čemur sledi simbolična oznaka samega operaterja.
  • Vgrajeni operaterji so definirani tako, da obstaja povezava med njimi. Na primer, naslednji operaterji so enakovredni drug drugemu: ++ x-x + = 1- x = x + 1. Po redefiniranju se razmerje med njimi ne bo ohranilo. Ohranjanje njihovega timskega dela na ta način z novimi tipi programerjev bo treba poskrbeti ločeno.
  • Prevajalnik ne ve, kako razmišljati. Izrazi z + 5 in 5 + z (kjer je z kompleksno število) bo prevajalnik različno obravnaval. Prva je "kompleksna + številka", druga pa "številka + kompleksna". Zato morate za vsak izraz določiti lasten operater dodajanja.
  • Pri iskanju definicije operaterja prevajalec ne daje prednost funkcijam člana razreda niti pomožnim funkcijam, ki so določene zunaj razreda. Za prevajalce so enaki.

Interpretacija binarnih in enotnih operaterjev.

Binarno delovanje

Binarni operater je definiran kot funkcija člana z eno spremenljivko ali funkcijo z dvema spremenljivkama. Za vsak binarni operator @ so v izrazu a @ b, @ veljavne naslednje konstrukcije:

a.operator @ (b) ali operator @ (a, b).

Razmislite o primeru vrste zapletenih številk opredelitev operacij kot članov razreda in pomožnih.

razred kompleksa {double re, im-public: kompleksen operator + = (kompleks z) -kompleks operater + (kompleks z1, kompleks z2) -kompleks operator + (kompleks z, dvojna a) -

Kateri izmed operaterjev bo izbran in ali bo sploh izbran, so določeni z notranjimi mehanizmi jezika, o katerih bomo razpravljali v nadaljevanju. Ponavadi se to zgodi z ujemanjem tipa.

Izbira, opisujejo funkcijo kot člana razreda ali zunaj, je na splošno odvisna od okusa. V zgornjem primeru je načelo izbire, kot sledi: če je operacija spremeni levi operand (na primer, a + = b), nato pa ga evidentira v razredu in uporabo stopenjski menjalnik na, za njeno takojšnjo Changes- če operacija ne spremeni ničesar in samo vrne novo vrednost ( na primer, a + b) presega definicijo razreda.

Jedrske in binarne operacije

Določitev preobremenitve enotnih operaterjev v C + + poteka na podoben način, z razliko, da so razdeljeni v dve vrsti:

  • predpono operator, ki se nahaja pred operandom, - @a, na primer, ++ i. o je definiran kot a.operator @ () ali operator @ (aa);
  • operator postfix, ki se nahaja po operandu - b @, na primer, i ++. o je definiran kot b.operator @ (int) ali operator @ (b, int)

Na enak način kot pri binarnih operaterjih za primer, ko je izjava operaterja tako v razredu kot izven razreda, bodo izbirali mehanizmi C + +.

Pravila za izbiro operaterja

Vrste operaterjev C ++

Naj bo binarni operator @ uporabljen za predmete x iz razredov X in y iz razreda Y. Pravila za razrešitev x @ y bodo naslednja:

  1. če je X razred, ga preglejte za opredelitev operaterja @ kot člana X ali osnovnega razreda X;
  2. si oglejte kontekst, v katerem se nahaja izraz x @ y;
  3. če se X nanaša na prostor imen N, poiščite izjavo operaterja v N;
  4. če se Y nanaša na imensko površino M, poiščite izjavo operaterja v M.

V primeru, da je v 1-4 najdenih več obvestil operaterja @, bo izbira izvedena v skladu s pravili za reševanje preobremenjenih funkcij.

Iskanje enotnih operaterjev je popolnoma enako.

Pojasnjena opredelitev kompleksa

Zdaj bomo zgradili razred kompleksnih številk na podrobnejši način, da bi pokazali številna predhodno izražena pravila.

razred kompleksa {double re, im-public: kompleksen operator + = (kompleks z) {// deluje z izrazi oblike z1 + = z2re + = z.re-im + = z.im-vrnitev * this-} kompleks Operator + = (dvojna a) {// deluje z izrazi z1 oblike + = 5-re + = a-donos * to-} kompleks (): re (0) im (0) {} // privzeti konstruktor za inicializacijo . Tako bodo vse deklarirane kompleksne številke imele začetne vrednosti kompleksa (0, 0) kompleksne (dvojne r): re (r), im (0) {} // omogoči ekspresijo oblike kompleksa z = 11 - enakovreden zapis z = kompleks (11) -kompleksa (dvojna r, dvojna i): re (r), im (i) {} // konstruktor} -kompleksa Operator + (Kompleksna Z1, Z2 kompleks) {// deluje z izrazi z1 oblike + z2complex RES = Z1-povratna ločljivosti + = Z2- // operater uporaba definirana kot funkcija člana} kompleksu Operator + (kompleks z dvojno a) {// ročaj izrazi obliki z + 2complex RES = z-povratna ločljivosti + = a-} kompleksu Operator + (Double a, kompleks z) {// obdeluje izraze obliki 7 + zcomplex RES = z-povratna ločljivosti + = a -} // hellip-

Kot lahko vidite iz kod, preobremenitev operaterja ima zelo zapleten mehanizem, ki lahko zelo raste. Vendar takšen podroben pristop omogoča preobremenitev tudi za zelo zapletene podatkovne strukture. Na primer, preobremenitev stavkov C ++ v razredu predlog.

Takšno oblikovanje funkcij za vsakogar in vse je lahko moteče in vodi do napak. Če na primer dodate tretjo vrsto za obravnavane funkcije, boste morali razmisliti o operacijah zaradi kombinacije treh vrst. Potrebno je napisati 3 funkcije z enim argumentom, 9 - z dvema in 27 - s tremi. Zato je v številnih primerih izvajanje vseh teh funkcij in znatno zmanjšanje njihovega števila mogoče doseči z uporabo konverzij tipa.

Posebni operaterji

Operator indeksa "[]" mora biti vedno opredeljen kot član razreda, saj zmanjša obnašanje objekta v matriki. Argument indeksiranja je lahko katerikoli tip, ki omogoča ustvarjanje, na primer, asociativnih nizov.

Operater za klicanje funkcije "()" lahko šteje za binarno operacijo. Na primer, v izrazu (seznam izrazov) gradi, je levi operand binarnega delovanja () izraz, desni pa je seznam izrazov. Funkcija operator () () mora biti član razreda.

Operater zaporedja "," (vejica) je pozvan za predmete, če je poleg njih tudi vejica. Vendar operator ne sodeluje pri štetju argumentov funkcij.

Operater dereferencing "->" mora biti tudi opredeljen kot član funkcije. V njegovem pomenu lahko definiramo kot unary postfix operater. V tem primeru mora nujno vrniti povezavo ali kazalec, ki omogoča dostop do predmeta.

Nosilec naloge Prav tako je opredeljen le kot član razreda zaradi svoje povezave z levim operandom.

Operateri dodeljevanja "=", naslovi "" in zaporedja "," morajo biti opredeljeni v javnem bloku.

Rezultat

Preobremenitev operaterji pomagajo pri izvajanju enega od ključnih vidikov OOP o polimorfizmu. Pomembno pa je razumeti, da preobremenitev ni le drugačen način klicanja funkcij. Naloga operaterjev preobremenitve je pogosto izboljšati razumevanje kode, namesto da bi zagotovili dobitke pri nekaterih vprašanjih.

Kaj je polimorfizem?

In to ni vse. Prav tako je treba upoštevati, da je preobremenitev operaterja kompleksen mehanizem z veliko pasti. Zato je zelo težko narediti napako. To je glavni razlog, zakaj večina programerjev svetuje, da se vzdržijo uporabe preobremenitve operaterja in da se zatečejo k njej le kot zadnja možnost in s polnim zaupanjem v svoja dejanja.

Priporočila

C ++ Creator Bjarne Stroustrup
  1. Izvajati preobremenitev operaterja samo za simulacijo znanih zapisov. Da bi bila koda bolj berljiva. Če koda postane bolj zapletena v strukturi ali berljivosti, se izogibajte preobremenitvi operaterjev in uporabite funkcije.
  2. Za velike operande, da bi prihranili prostor, uporabite argumente z vrsto stalnih referenc za prenos.
  3. Optimizirajte povratne vrednosti.
  4. Ne dotikajte se kopiranja, če je primerna za vaš razred.
  5. Če kopiranje privzeto ne deluje, spremeni ali izrecno prepove kopiranje.
  6. V primerih, ko funkcije zahtevajo dostop do predstavitve razreda, bi morali raje imeti funkcije članstva nad nečlanskimi funkcijami.
  7. Določite imenski prostor in označite odnos funkcij v njihovem razredu.
  8. Uporabite funkcije nečlanov za simetrične operaterje.
  9. Uporabite operator () za indekse v večdimenzionalnih nizih.
  10. Bodite previdni pri implicitnih preusmeritvah.
Zdieľať na sociálnych sieťach:

Príbuzný