C++-manual
Förutgående | Kapitel 21. Överlagring av operatorer | Nästa

# Överlagring och friends

I normal vektoraritmetik kan man multiplicera vektorer med skalärer, d.v.s. vanliga tal för att ändra vektorns längd. Man multiplicerar då varje komponent med talet. Vi överlagra `*` på följande sätt:

    // prototyp
    Vector operator* (const float S) const;

    // implementation
    Vector Vector::operator* (const float S) const {
      Vector Result;

      // sätt den nya vektorns värden
      Result.setX ( m_X * S );
      Result.setY ( m_Y * S );
      Result.setZ ( m_Z * S );

      // returnera den nya vektorn
      return Result;
    }

Vi kan nu skriva kod på t.ex. följande sätt:

    #include <iostream>
    #include "Vector5.h"

    int main () {
      Vector V1 ( 1, 2, 3 );

      // multiplicera med skalär
      Vector Result = V1 * 3;

      cout << "x=" << Result.x () << ", "
           << "y=" << Result.y () << ", "
           << "z=" << Result.z () << endl;
    }

Kör vi programmet ovan får vi följande resultat:

    % ./TestVector5
    x=3, y=6, z=9
    %

Vi ser att varje komponent multiplicerats med tre, precis som vi avsåg. Men vad händer om vi istället skriver något i stil med följande:

    Vector V1 ( 1, 2, 3 );

    // multiplicera med skalär
    Vector Result = 3.0 * V1;

Detta skulle innebära att datatypen `float` borde ha operatorn `*` överlagrad på ungefär följande sätt:

    float.operator* (Vector);

Någon dylik funktion/metod finns inte. Vi märker alltså att det är den vänstra operanden som måste ha metoden överlagrad, och primitiva datatyper har inga överlagringar för icke-primitiva datatyper (såsom t.ex. `Vector` i vårt fall). Vi kan göra det enkelt för oss och säga att man måste ha skalärer till höger om en `Vector` då man utför multiplikation med skalär, men det är ointuitivt och leder till onödiga problem för programmeraren.

Lösningen är att använda en funktion som inte är medlem av klassen `Vector`.

## Friend-funktioner

Eftersom det är omöjligt att definiera en metod för klassen `Vector` så att man kan multiplicera från vänster med en skalär skapar vi en funktion som är utanför klassen helt och hållet. Eftersom det är en vanlig funktion behöver man inget objekt för att anropa metoden, men istället tar den två parametrar, en `float` och en `Vector`. Vad vi gör är alltså att vi definierar om den generella operatorn `+` för argumenten `float` och `Vector`. Koden ser ut på följande sätt:

    // prototyp
    friend Vector operator* (const float S, const Vector & V);

    // implementation
    Vector operator* (const float S, const Vector & V) {
      // använd tidigare överlagrad operator '*'
      return V * S;
    }

Notera att vi definierar funktionen som en friend till klassen `Vector` (för mera information om friends se avsnittet Friends i Kapitel 17). På det sättet kan funktionen accessera privata data i parametern `V` om så skulle behövas. Vi har dock gjort funktionen elegant och använder oss av den tidigare överlagrade operatorn `*` som tillhör klassen. För att kunna göra detta så reverserar vi ordningen på `S` och `V`, och får en multiplikation mellan en `Vector` och en `float`, vilket ju kan hanteras av den tidigare versionen.

Vi kan nu skriva t.ex. följande kod utan problem:

    Vector V1 ( 1, 2, 3 );

    // multiplicera med skalär
    Vector Result = 3.0 * V1;

Ovanstående funktion blir om man använder sig av den oföskönade syntaxen följande:

    Vector V1 ( 1, 2, 3 );

    // multiplicera med skalär
    Vector Result = operator* (3.0, V1);

Vi kunde om vi ville definiera alla överlagrade operatorer som funktioner på samma sätt som vi gjorde ovan, men det är inte speciellt vackert och bryter emot principen att kapsla ihop kod som har med en klass att göra med klassen själv. Viss funktionalitet måste dock implementeras via friend-funktioner.

Förutgående | Hem | Nästa
Överlagring av operatorn `-` | Upp | Operatorerna `==` och `=`