TI-S2

Meer operatoren (title-id)

Inhoud

Meer operatoren

We hebben gezien, in operatoren hoe een operator+ en een operator- voor vectoren kan worden gemaakt.

Van een echte ADT verwacht de gebruiker veel meer operatoren. Als een ADT een operator+ en een operator= (assignment) heeft, dan verwacht je ook een operator+=. Die moet, anders dan een operator+, zijn linker argument wijzigen. Dat argument moet dus ‘by reference’ worden doorgegeven (dat is automatisch zo) maar anders dan bij de operator+ niet ‘als const’.

Gebruik references in operatoren

De C++ gewoonte is dat het resultaat van een assignment-achtige operator (=, +=, -=, etc.) een reference is naar het object zelf. Anders dus dan bij de operator+, daar is het resultaat een waarde. Het rechter argument (rhs: right hand side) wordt voor beide operatoren op de zelfde wijze doorgegeven: by const reference.

class vector {
public:
    int x;
    int y; 
    vector operator+( const vector & rhs ) const; 
    vector & operator+=( const vector & rhs );
};

Codevoorbeeld 06-10 - Een vector klasse met operatoren + en +=

Implementatie operator+=

De implementatie van de operator+= is simpel:

Pointers

Pointers worden later uitgebreider besproken. Je kunt een pointer zien als een soort reference waarbij je met een * expliciet moet aangeven dat je het aangewezen object bedoelt, en niet de pointer zelf. Bij een reference gaat dat automatisch.

  vector & vector::operator+=( const
    vector & rhs ){ 
        x += rhs.x; 
        y += rhs.y; 
        return *this; 
    }

Codevoorbeeld 06-10 - Implementatie van operator+=

Verschil operator+ en operator+=

De operator+ en operator+= doen gedeeltelijk hetzelfde: twee vectoren optellen. Het verschil is waar ze het resultaat laten:

Don’t Repeat Yourself

Als wat zo’n koppel operatoren doet wat minder triviaal is dan is het een goed idee om dit maar één keer op te schrijven: DRY (Don’t Repeat Yourself).

De eenvoudigste manier is om de operator+= te implementeren zoals we al zagen, en dan de operator+ te implementeren door een kopie te maken van onze eigen waarde, daar de operatror+= op los te laten, en dan die kopie te returnen. Dit lijkt misschien wat omslachtig, maar de winst is dat deze drie regels helemaal onafhankelijk zijn van wat ‘optellen’ voor de klasse precies inhoudt: deze drie regels vind je dus in vrijwel alle operator+ implementaties.

vector vector::operator+( const vector & rhs ) const { 
    vector temp = *this;
    temp += rhs;
    return temp; 
}

Codevoorbeeld 6-10 - Implementatie van operator+ door gebruik te maken van operator+=

Operator: methode of ‘vrije’ functie?

Je kunt veel (maar niet alle) operatoren naar keuze als methode (klasse functie) schrijven of als ‘vrije’ functie (los van een klasse).

De vuistregel is dat je een operator als methode (klasse functie) schrijft, tenzij dat niet kan.

class vector {
public:
  int x;
  int y;
  . . . 

  // operator+ methode (binnen de klasse)
  vector operator+( const vector & rhs ) const { 
    return vector( x + rhs.x, y + rhs.y ); 
    }

  };

// operator- functie (buiten de klasse)
vector operator-( const vector & lhs, const vector & rhs ){ 
  return vector( lhs.x - rhs.x, lhs.y + rhs.y ); 
}

Codevoorbeeld 06-11 - Een methode operator+ en een losse functie operator-

Vaste lijst operatoren en prio’s

In C++ kunnen veel operatoren door de gebruiker worden gedefinieerd, maar,

Je kunt dus géén nieuwe operator $ of ^^ maken.

Tabel belangrijkste operatoren

De onderstaande tabel geeft de belangrijkste operatoren weer die je in C++ zelf kunt definiëren. Slechts een klein deel daarvan behandelen we hier.

De meeste operatoren kun je op twee manieren schrijven:

Monadic operator

Je kunt ook een operator+() methode met 1 parameter maken (in het geval van een klasse functie dus géén parameter), dat is dan de (minder nuttige) ‘monadic’ plus, die bv. wordt aangeroepen met a = +b.

Let op: a = +b is iets anders dan a += b!.

alt text ad. 30: Een extra (dummy) integer parameter wordt meegegeven door de compiler om de prefix operator te onderscheiden van de postfix versie. ad. 31: De « en » operatoren worden eigenlijk altijd als losstaande functies geschreven, omdat het voor het algemeen aanvaarde gebruik van deze operatoren (geformatteerde tekst input en output) nodig is dat het linker argument van het type std::istream of std::ostream kan zijn, en aan die klassen kan een gebruiker niets toevoegen. ad. 32: Deze operatoren kunnen alleen als methode worden gedefinieerd, niet als vrije functie.

Naamgeving en verwachtingsmanagement

Aangezien een operator niet zoals een methode of functie een lange, betekenisvolle naam kan hebben is het erg belangrijk dat de gebruiker van een operator krijgt wat hij verwacht.

Dit beperkt het gebruik van operatoren tot bv. typen waarmee je kunt rekenen, zoals meetwaarden, vectoren, en imaginaire getallen. Twee strings bij elkaar optellen heeft voor de meeste mensen ook nog wel een intuïtieve betekenis, en een string met een integer vermenigvuldigen eventueel ook nog (s * 5 is dan het zelfde als s + s + s + s + s).

Maar strings van elkaar aftrekken of een string delen door een getal is voor bijna alle argeloze lezers van zo’n stukje code betekenisloos.

<< en >> operatoren

De operatoren << en >> hebben een standaard betekenis (tekst-output en -input) die later nog besproken wordt.

&& en || operatoren

De ingebouwde && en || operatoren (logische and en or) hebben een short-circuit eigenschap. Eerst wordt de linker waarde bepaald. Als met die waarde het resultaat van de operator al vast staat (voor welke combinaties van operatoren en waarden is dat zo?) dan wordt de rechter waarde niet meer uitgerekend. Dit kan van groot belang zijn als het bepalen van die rechter waarde een probleem zou opleveren.

Een door de gebruiker gedefinieerde && of || operator heeft nooit deze short-circuit eigenschap: beide waarden worden eerst uitgerekend, en dan pas wordt de (door de gebruiker gedefinieerde) operator functie aangeroepen.

Tips: zelf operatoren schrijven

Na al die waarschuwingen vraag je je misschien af of het überhaupt wel verstandig is om zelf operatoren te definiëren.

Een paar vuistregels:

Tekst operatoren

Reken operatoren

Advies: definieer niet alles zelf