V vsaki znanosti obstajajo standardni zapisi, ki olajšujejo razumevanje idej. Na primer, v matematiki gre za množenje, delitev, dodatek in drugo simbolno notacijo. Izraz (x + y * z) je veliko lažje razumeti kot "pomnožiti y, z in dodati v x". Predstavljajte si, da do XVI. Stoletja matematika ni imela simbolne oznake, vsi izrazi so bili napisani verbalno, kot da je umetniško besedilo z opisom. In navadni znaki delovanja za nas so se pojavili kasneje. Težko je preceniti pomen kratkega zapisa znakov. Na podlagi teh premislekov so programski jeziki dodali preobremenitvi operaterjev. Razmislite o primeru.
Primer preobremenitve operaterja
//zamislite kompleksno število v obliki para števil zplavajoči vejici.
razredni kompleks {{12} dvojni re, im;
javno:
kompleksno (dvojno r, dvojno i): re (r), im (i) {} //konstruktor
kompleksni operator + (kompleks); //preobremenitveni sklop
kompleksni operator * (kompleksen); //preobremenitev množenja
};
prazen glavni () {
kompleks a {1 2}, b {3}}, c {0}};
c = a + b;
c = a.operator + (b); ////operacijsko funkcijo lahko imenujemo poljubna funkcija, ta vnos je enakovreden a + b
c = a * b + kompleksu (1 3); //Izvedemo običajna pravila o prednostih operacij seštevanja in množenja
}
Podobno lahko naredimo, na primer, preobremenitve I /O operaterjev v C ++ in jih prilagodimo izhodom tako kompleksnih struktur kot matrik.
Upravljavci, ki so na voljo za preobremenitev
Popoln seznam vseh izvajalcev, za katere se lahko uporabi mehanizem za preobremenitev:
+*/ 39]novanovo []
% | ^ | in str. | ||||
| | ~ | ! | = | & gt; | + = | |
- = | * = | /= | ^ = | in | | 62] | |
= | = | == 84] | ! = | |||
> = | in str. | | | ++ | - * | , | |
- & gt; | izbriši | delete [] |
Kot je razvidno iz tabele, je preobremenitev dovoljena za večino operaterjev. Operaterja ni treba preobremeniti. To je zgolj zaradi udobja. Zato je na primer preobremenitev operaterjev v Javi odsotna. In zdaj o tako pomembnem trenutku.
Operaterji, katerih preobremenitev je prepovedana
- Dovoljenje za vidljivost - «::»;
- Izbira člana je ".";
- Izbira člana s kazalcem na člana - ". *";
- Ternarni pogojni operater - «?:»;
- velikost operaterja;
- Upravljavec tipa.
Pravi operand podatkov operaterjev je ime, ne vrednost. Zato bi dovoljenje za njihovo preobremenitev lahko pripeljalo do pisanja številnih dvoumnih modelov in bi močno otežilo življenje programerjev. Čeprav obstaja veliko programskih jezikov, ki omogočajo preobremenitev vseh operaterjev - na primer preobremenitev Python operaterjev.
& lt; script type = "text /javascript" & gt;
lahko blockSettings2 = {blockId: "R-A-70350-2", renderTo: "yandex_rtb_R-A-70350-2", async:! 0};
če (document.cookie.indexOf ("abmatch ="))> = 0) {
blockSettings2 = {blockId: "RA-70350-2", renderTo: "yandex_rtb_R-A-70350- 2 ", statId: 70350async: 0};
}
Funkcija (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (funkcija () {Ya .Context.AdvManager.render (blockSettings2)}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex.ru/system/context.js", d.async =! 0e.parentNode.insertBefore (d, e)} (to, ta.dokument, "yandexContextAsyncCallbacks");
Omejitve
Omejevanje preobremenitve upravljavca:
- Binarnega operaterja ne morete spremeniti na unarnem in obratno, saj ne morete dodati tretjega operanda.
- Ne morete ustvariti novih operaterjev, razen tistih, ki so. Ta omejitevspodbuja odpravo številnih dvoumnosti. Če potrebujete novega operaterja, lahko uporabite funkcijo, ki bo za te namene izvedla želeno dejanje.
- Operatorska funkcija je lahko član razreda ali ima vsaj en tip argumenta. Izjema so novi in izbrisani operaterji. To pravilo prepoveduje spreminjanje pomena izrazov, če ne vsebujejo uporabniško definiranih vrst objektov. Zlasti ne morete ustvariti operaterjeve funkcije, ki bi delovala samo s kazalci ali prisilila operaterja dodatka, da deluje kot množenje. Izjeme so operatorji "=", "& amp;" in "," za predmete razreda.
- Operativna funkcija s prvim izrazom, ki pripada enemu od vgrajenih tipov podatkov v jeziku C ++, ne more biti član razreda.
- Ime katere koli operacijske funkcije se začne s ključnim operaterjem, ki mu sledi simbolična oznaka samega operaterja.
- Vgrajeni upravljavci so opredeljeni tako, da obstaja povezava med njimi. Naslednji operaterji so na primer enakovredni: ++ x; x + = 1; x = x + 1. Po ponovni določitvi povezave med njima ne bo ohranjena. O ohranjanju njihovega dela na podoben način z novimi vrstami programerjev bodo morali skrbeti zase.
- Prevajalnik ne more razmišljati. Izrazi z + 5 in 5 + z (kjer je z - kompleksno število) bo prevajalnik obravnaval na različne načine. Prva je "kompleksna + številka", druga pa "kompleksna številka +". Zato morate za vsak izraz definirati lastno izjavo o dodatku.
- Pri iskanju definicije operatorja prevajalnik ne daje prednosti nobenemu funkcijskemu članu razreda, niti pomožnim funkcijam,ki so opredeljene izven razreda. Za prevajalnik so enaki.
Razlaga binarnih in unarnih operaterjev.
Binarni operator je opredeljen kot funkcija člana z eno spremenljivko ali kot funkcija z dvema spremenljivkama. Za vsak binarni operator @ je izraz a @ b @ veljaven konstrukt:
& lt; script type = "text /javascript" & gt;
lahko blockSettings3 = {blockId: "R-A-70350-3", renderTo: "yandex_rtb_R-A-70350-3", async:! 0};
blockSettings3 = {blockId: "RA-70350-3", renderTo: "yandex_rtb_R-A-70350-" 3 ", statId: 70350async: 0};
}
Funkcija (a, b, c, d, e) {a [c] = a [c] || [], a [c] .push (funkcija () {Ya .Context.AdvManager.render (blockSettings3)}), e = b.getElementsByTagName ("script") , d = b.createElement ("script"), d.type = "text /javascript", d.src = "//an.yandex.ru/system/context.js", d.async =! 0e.parentNode.insertBefore (d, e)} (to, ta.dokument, "yandexContextAsyncCallbacks");
a.operator @ (b) ali operator @ (a, b).
Razmislite primer razreda kompleksnih števil za definicijo operacij kot članov razreda in pomožnega.
Razredni kompleks {{174} dvojni re, im;
javna:
kompleksna; operator + = (kompleksno z);
kompleksni & amp; operator * = (kompleksno z);
};
//pomožne funkcije
kompleksni operator + (kompleksno z1 kompleksno z2);
kompleksni operator + (kompleksno z, dvojno a);
Kateri od operaterjev bo izbran in ali bo sploh izbran, je določen z notranjimi mehanizmi jezika, ki bodo obravnavani spodaj. Običajno se to zgodi v skladu s tipi.
Izbira, ki opisuje funkcijo člana razreda ali zunaj njega - na splošno okus. V zgornjem primeru je bilo načelo izbire naslednje: če operacija spremeni levi operand (npr. A + = b), ga zapišite znotraj razreda in uporabite prenos spremenljivke na naslov za njegovo neposredno spremembo; če operacija ni ničspremeni in preprosto vrne novo vrednost (na primer a + b) - po definiciji razreda.
Opredelitev preobremenitve unarnih operaterjev v C ++ se pojavlja na enak način, z razliko, da so razdeljeni na dva tipa:
- predpono operaterja, ki se nahaja na operandu, - @, na primer, i ++. o Definiran kot a.operator @ () ali operator @ (aa);
- postfix operater, ki se nahaja za operandom, - b @, na primer, i ++. o Opredeljeno kot b.operator @ (int) ali operator @ (b, int)
Tako kot pri binarnih operaterjih, v primeru, ko je izjava operatorja v razredu in zunaj razreda, bo izbira izvedena z mehanizmi C ++.
Pravila za izbiro operaterja
Naj bo binarni operator @ uporabljen za objekte x razreda X in y razreda Y. Pravila za ločljivost x @ y bodo naslednja:
- če je X razred, v njem poiščite definicijo operatorja @ kot izraz X ali osnovni razred X;
- , da si ogledajo kontekst, v katerem se nahaja izraz x @ y;
- če X pripada imenskem prostoru N, poiščite izjavo operaterja N;
- Če Y pripada imenskem prostoru M, poiščite izjavo operatorja M.
Če je bilo v 1-4 najdenih več izjav operatorjevega operaterja @, bo izbira izvedena v skladu s pravili dovoljenja preobremenjenih funkcij.
Iskanje unarnih operaterjev se izvaja na povsem enak način.
Izboljšati definicijo razrednega kompleksa
Zdaj bomo konstruirali razred kompleksnih številk na bolj podroben način.pokazati številna predhodno objavljena pravila.
razredni kompleks {
dvojno ponovno, im;
javna:
kompleksna & amp; operator + = (kompleks z) {//deluje z izrazi oblike z1 + = z2
re + = z.re;
im + = z.im;
vrni * to;
}
kompleksen & amp; operator + = (double a) {//deluje z izrazi oblike z1 + = 5;
re + = a;
vrne * to;
}
kompleks (): re , im
{} //konstruktor za privzeto inicializacijo. Tako bodo vsa deklarirana celoštevilčna števila imela začetne vrednosti (0 0)
kompleksne (dvojne r): re (r), im
{} //konstruktor naredi izraz oblike kompleksno z = 11; enakovredna zapisu z = kompleks
;
kompleks (dvojno r, dvojno i): re (r), im (i) {} //konstruktor
};
kompleksni operater + (kompleksno z1 kompleksno z2) {//deluje z izrazi oblike z1 + z2
kompleksa res = z1;
vrne res + = z2; //uporabimo operator, definiran kot funkcijo člana
}
kompleksni operator + (kompleksno z, dvojno a) {//obravnava izraze oblike z + 2
kompleksa res = z;
vrne res + = a;
}
kompleksni operator + (double a, complex z) {//obdeluje izraze oblike 7 + z
kompleksa res = z;
vrne res + = a;
}
//
Kot je razvidno iz kodeksa, ima preobremenjenost operaterjev precej zapleten mehanizem, ki lahko močno raste. Vendar pa takšen podroben pristop omogoča preobremenitev tudi za zelo kompleksne strukture podatkov. Na primer, preobremenitev operaterjev C ++ v razredu predloge. Takšno ustvarjanje funkcij za vse in vse je lahko dolgočasno in vodi do napak. Če na primer dodate tretji tip obravnavanih funkcij, boste morali upoštevati operacije zaradi kombinacije treh vrst. Morali bomo napisati 3 funkcije z enim argumentom, 9 - z dvema in 27 - s tremi. Zato je v nekaterih primerih izvajanje vseh teh funkcij in njihovo znatno zmanjšanjeKoličine se lahko dosežejo s pretvorbo tipov.
;
kompleks (dvojno r, dvojno i): re (r), im (i) {} //konstruktor
};
kompleksni operater + (kompleksno z1 kompleksno z2) {//deluje z izrazi oblike z1 + z2
kompleksa res = z1;
vrne res + = z2; //uporabimo operator, definiran kot funkcijo člana
}
kompleksni operator + (kompleksno z, dvojno a) {//obravnava izraze oblike z + 2
kompleksa res = z;
vrne res + = a;
}
kompleksni operator + (double a, complex z) {//obdeluje izraze oblike 7 + z
kompleksa res = z;
vrne res + = a;
}
//