Kādi ir operatoru pārslodzes pamatnoteikumi un idiomas?

Piezīme: Atbildes tika sniegtas noteiktā secībā, bet, tā kā daudzi lietotāji šķiro atbildes pēc balsojuma, nevis pēc to sniegšanas laika, šeit ir sniegts ___atbilžu indekss tādā secībā, kādā tām ir vislielākā nozīme:

(Piezīme: Šis ir domāts kā ieraksts Stack Overflow's C++ FAQ. Ja vēlaties kritizēt ideju par FAQ nodrošināšanu šādā formā, tad meta ieraksts, ar kuru tas viss sākās būtu īstā vieta, kur to darīt. Atbildes uz šo jautājumu tiek uzraudzītas C++ tērzētavā, kur FAQ ideja aizsākās vispirms, tāpēc ļoti iespējams, ka jūsu atbildi izlasīs tie, kas ierosināja šo ideju).

Bieži pārslodzes operatori

Lielākā daļa no operatora pārslodzes darba ir kopējais kods. Tas nav nekāds brīnums, jo operatori ir tikai sintaktiskais cukurs, un to faktisko darbu varētu veikt (un bieži vien arī tiek nodots) vienkāršas funkcijas. Taču ir svarīgi, lai šis "boilerplate" kods būtu pareizs. Ja jums tas neizdosies, vai nu jūsu operatora kods netiks kompilēts, vai arī jūsu lietotāju kods netiks kompilēts, vai arī lietotāju kods uzvedīsies pārsteidzoši.

Piešķiršanas operators

Par piešķiršanu var daudz ko teikt. Tomēr lielākā daļa no tā jau ir teikta GMan's slavenajā Copy-And-Swap FAQ, tāpēc es šeit izlaidīšu lielāko daļu no tā, tikai atsauces nolūkos uzskaitot perfektu piešķiršanas operatoru:

X& X::operator=(X rhs)
{
  swap(rhs);
  return *this;
}

Bitshift operatori (izmanto plūsmas I/O)

Lai gan bitshift operatori `` joprojām tiek izmantoti aparatūras saskarnēs, lai gan tie ir bitu manipulācijas funkcijas, kas pārmantotas no C, lielākajā daļā lietojumprogrammu tie ir kļuvuši izplatītāki kā pārslogoti plūsmas ieejas un izejas operatori. Norādījumus par pārslodzi kā bitu manipulācijas operatoriem skatiet tālāk sadaļā par binārajiem aritmētiskajiem operatoriem. Lai īstenotu savu pielāgotu formāta un parsēšanas loģiku, kad jūsu objekts tiek izmantots ar iotecēm, turpiniet. Straumju operatori, kas ir vieni no visbiežāk pārslogotajiem operatoriem, ir bināri infiksa operatori, kuriem sintakse nenosaka ierobežojumus attiecībā uz to, vai tiem jābūt locekļiem vai locekļiem. Tā kā tie maina savu kreiso argumentu (maina plūsmas stāvokli), saskaņā ar vispārpieņemtajiem noteikumiem tie jārealizē kā sava kreisā operanda tipa locekļi. Tomēr to kreisie operandi ir standarta bibliotēkas plūsmas, un, lai gan lielākā daļa standarta bibliotēkā definēto plūsmas izvades un ievades operatoru patiešām ir definēti kā plūsmas klašu locekļi, īstenojot izvades un ievades operācijas saviem tipiem, jūs nevarat mainīt standarta bibliotēkas plūsmas tipus. Tāpēc šie operatori saviem tipiem jārealizē kā funkcijas, kas nav biedru funkcijas. Abu šo operāciju kanoniskās formas ir šādas:

std::ostream& operator(std::istream& is, T& obj)
{
  // read obj from stream

  if( /* no valid object of T found in stream */ )
    is.setstate(std::ios::failbit);

  return is;
}

Īstenojot operatoru>>>, manuāli iestatīt plūsmas stāvokli ir nepieciešams tikai tad, ja pati lasīšana ir izdevusies, bet rezultāts nav tāds, kāds būtu gaidīts.

Funkcijas izsaukuma operators

Funkcijas izsaukuma operatoram, ko izmanto funkciju objektu, pazīstamu arī kā funktori, izveidei, jābūt definētam kā member funkcijai, tāpēc tam vienmēr ir netiešais this arguments kā member funkcijām. Papildus tam to var pārslogot, lai tas varētu pieņemt jebkuru papildu argumentu skaitu, ieskaitot nulli. Lūk, sintakses piemērs:

class foo {
public:
    // Overloaded call operator
    int operator()(const std::string& y) {
        // ...
    }
};

Lietošana:

foo f;
int a = f("hello");

Visā C++ standarta bibliotēkā funkciju objekti vienmēr tiek kopēti. Tāpēc jūsu pašu funkciju objektiem jābūt lētiem, lai tos varētu kopēt. Ja funkcijas objektam noteikti jāizmanto dati, kuru kopēšana ir dārga, labāk šos datus glabāt citur un funkcijas objektam uz tiem atsaukties.

Salīdzināšanas operatori

Bināro infiksu salīdzināšanas operatori saskaņā ar īkšķa noteikumiem jārealizē kā funkcijas, kas nav biedru funkcijas1. Vienbalsīga prefiksa noliegums ! (saskaņā ar tiem pašiem noteikumiem) jārealizē kā locekļa funkcija. (bet parasti nav laba ideja to pārslogot.) Standarta bibliotēkas algoritmi (piemēram, std::sort()) un tipi (piemēram, std::map) vienmēr sagaida tikai operator, ja vērtības_tips ir klases (vai konstrukcijas, vai vienības) tips, rekursīvi tiek izsaukts cits operators->(), līdz operators->() atgriež vērtību, kas nav klases tipa. Vienpakāpes operatoru address-of nekad nedrīkst pārslogot. Par operator->*() skat. šis jautājums. Tas tiek reti izmantots un tāpēc reti kad tiek pārslogots. Patiesībā pat iteratori to nepārslogo.

Turpināt uz Pārveidošanas operatori

Komentāri (70)

Tri pamatnoteikumi par operatora pārslodzes lietošanu C++

Runājot par operatoru pārslodzi C++, ir trīs pamatnoteikumi, kas jāievēro. Tāpat kā visos šādos noteikumos, arī šeit ir izņēmumi. Dažreiz cilvēki ir novirzījušies no tiem, un rezultāts nav bijis slikts kods, taču šādu pozitīvu noviržu ir maz un tās ir ļoti retas. Vismaz 99 no 100 šādām atkāpēm, ko esmu redzējis, bija nepamatotas. Tomēr tikpat labi tās varētu būt bijušas 999 no 1000. Tāpēc labāk turieties pie šādiem noteikumiem.

  1. Ja kāda operatora nozīme nav acīmredzami skaidra un neapstrīdama, to nevajadzētu pārslogot. Vai vietā piedāvājiet funkciju ar labi izvēlētu nosaukumu. Būtībā pirmais un galvenais operators pārslogošanas noteikums savā būtībā saka: Nedariet tā. Tas var šķist dīvaini, jo par operatoru pārslodzi ir daudz kas jāzina, tāpēc par to ir daudz rakstu, grāmatu nodaļu un citu tekstu. Taču, neraugoties uz šo šķietami acīmredzamo pierādījumu, ir tikai pārsteidzoši maz gadījumu, kad operatoru pārslodze ir piemērota. Iemesls ir tāds, ka patiesībā ir grūti saprast operatora lietojuma semantiku, ja vien operatora lietojums lietojuma jomā nav labi zināms un neapstrīdams. Pretēji vispārpieņemtajam uzskatam, tas gandrīz nekad nenotiek.

  2. Visur pieturieties pie labi zināmās operatora semantikas.. C++ neuzliek nekādus ierobežojumus pārslogoto operatoru semantikai. Jūsu kompilators ar prieku pieņems kodu, kas implementē bināro + operatoru, lai atņemtu no tā labā operanda. Tomēr šāda operatora lietotāji nekad neiedomāsies, ka izteiksme a + b atņem a no b. Protams, tas nozīmē, ka operatora semantika lietojuma jomā ir neapstrīdama.

  3. Visas no saistīto operāciju kopas vienmēr sniedz visas . Operatori ir saistīti viens ar otru un ar citām operācijām. Ja jūsu tips atbalsta a + b, lietotāji sagaida, ka varēs izsaukt arī a += b. Ja tas atbalsta prefiksa inkrementu ++a, viņi sagaidīs, ka a++ arī darbosies. Ja viņi var pārbaudīt, vai a < b, viņi noteikti sagaida, ka varēs pārbaudīt arī, vai a > b. Ja viņi var kopēt jūsu tipu, viņi sagaida, ka darbosies arī piešķiršana.


Turpināt uz Lēmums starp locekli un ne-locekli.

Komentāri (43)

Operatora pārslodzes vispārējā sintakse C++

Operatoru nozīmi iebūvētajiem tipiem C++ nevar mainīt, operatorus var pārslogot tikai lietotāja definētajiem tipiem1. Tas nozīmē, ka vismaz vienam no operandiem jābūt lietotāja definētam tipam. Tāpat kā citas pārslogotās funkcijas, arī operatorus var pārslogot tikai vienreiz noteiktam parametru kopumam.

Ne visus operatorus var pārslogot programmā C++. Operatori, kurus nevar pārslogot, ir šādi: . :: :: `sizeof typeid .* un vienīgais trīskāršais operators C++, ?:.

No operatoriem, kurus var pārslogot, C++ ir šādi:

  • aritmētiskie operatori: + - * / % un += -= *= /= %= %= (visi bināri infiksi); + - (vienbalsīgs prefikss); ++ -- (vienbalsīgs prefikss un postfikss).
  • Bitu manipulācijas: &|`^ `un&=`|= ^= = >>= (visi binārie infiksi); ~ (vienbalsīgais prefikss)
  • bolu algebra: == != * , (visi bināri infiksi); * & (visi vienburtu prefiksi) () (funkcijas izsaukums, n-ārie infiksi)

Tomēr tas, ka jūs varat visas šīs funkcijas pārslogot, nenozīmē, ka jums vajadzētu to darīt. Skatiet operatoru pārslodzes pamatnoteikumus.

C++ valodā operatori tiek pārslogoti kā funkcijas ar īpašiem nosaukumiem. Tāpat kā citas funkcijas, arī pārslogotos operatorus parasti var īstenot vai nu kā to kreisā operanda tipa funkciju vai kā nefunkciju funkcijas___. Tas, vai jūs varat brīvi izvēlēties vai esat spiesti izmantot vienu no tām, ir atkarīgs no vairākiem kritērijiem. 2 Vienmandātu operatoru @3, ko piemēro objektam x, izsauc vai nu kā operator@(x), vai kā x.operator@(). Bināro infiksa operatoru @, ko piemēro objektiem x un y, izsauc vai nu kā operator@(x,y), vai kā x.operator@(y).4

Operatori, kas ir īstenoti kā funkcijas, kuras nav locekļu funkcijas, dažreiz ir draugi ar to operanda tipu.

1 Termins "lietotāja definēts" var būt nedaudz maldinošs. C++ izšķir iebūvētos tipus un lietotāja definētos tipus. Pie pirmajiem pieder, piemēram, int, char un double; pie otrajiem pieder visi struct, class, union un enum tipi, ieskaitot standarta bibliotēkas tipus, pat ja tie paši par sevi nav lietotāju definēti.

2 Tas ir aplūkots vēlākā daļā šajā FAQ.

3 @ nav derīgs operators C++, tāpēc es to izmantoju kā vietniekvārdu.

4 Vienīgais trīskāršais operators C++ valodā nav pārslogojams, un vienīgais n-ārais operators vienmēr jārealizē kā locekļa funkcija.


Turpināt uz Trīs pamatnoteikumi par operatora pārslodzi C++.

Komentāri (14)