C++-manual | ||
---|---|---|
Förutgående | Nästa |
Detta kapitel behandlar hur olika operatorer kan överlagras för att göra klasser mera transparenta för programmeraren.
I ett tidigare kapitel behandlade vi hur funktioner och metoder kan överlagras med hjälp av polymorfism (se avsnittet Polymorfism i Kapitel 17). Överlagring av metoder låter oss ha metoder med samma namn men som tar olika parametrar. På samma sätt kan man även överlagra operatorer i C++ och lägga till eller ändra funktionalitet. Vi kan på detta sätt definiera olika operatorer som annars inte kunde användas med någon viss klass att ha en meningsfull betydelse. Genom detta kan man göra olika klasser mera transparenta för användaren. De blir lättare och mera intuitiva att använda och påminner mera om primitiva datatyper såsom t.ex. int eller double.
En operator i C++ är en "symbol" som opererar på en datatyp. Det mesta av den text som binder ihop datatyper är olika operatorer. De olika operatorer som kan överlagras i C++ är följande:
Tabell 21-1. Operatorer som kan överlagras
+ | - | * | / | % | ^ | & |
| | ~ | ! | = | < | > | += |
-= | *= | /= | %= | ^= | &= | |= |
<< | >> | <<= | >>= | == | != | <= |
>= | && | || | ++ | ‐ | ->* | , |
-> | [] | () | new | new[] | delete | delete[] |
Inga andra operatorer än de ovannämda kan överlagras, men de flesta som är användbara finns bland dessa. Man vill relativt sällan överlagra andra än normala räkneoperatorer, jämförelse- och tilldelningsoperatorerna. Avancerade klasser som vill ha egen minneshantering kan dock överlagra t.ex. new och delete, men det ämnet går utanför detta kompendiums omfång. Se kursboken för mera information.
Då operatorer överlagras måste de bibehålla samma antal parametrar som de normalt gör. Man kan sålunda inte definiera en divisionsoperator (/) som tar en eller tre operander (parametrar). Divisionsoperatorn skall ha två operander. Däremot kan t.ex. operatorn minus (-) mycket väl ha en eller två parametrar, d.v.s. normal subtraktion (två parametrar) och negation (en parameter). Man kan inte ändra operatorers precedensordning från vad den är i normala fall. Enda möjligheten är att använda parenteser.
Det är inte heller vettigt att ändra på en operators funktionalitet genom överlagring. Det är helt möjligt att överlagra tilldelningsoperatorn till att skriva ut ett objekt på skärmen, men det är inte vettigt. Användaren har en grunduppfattning om vad som borde hända då t.ex. = används, och man bör inte ändra betydelsen. Man skall bibehålla operatorers normala betydelse, och endast göra funktionaliteten bättre om den redan finns, och implementera den normala funktionaliteten om operatorn inte redan kan användas tillsammans med klassen i fråga.
I detta kapitel skall vi behandla en klass Vector som ett genomgående exempel. Vi kommer att börja från en enkel klass och därefter överlagra olika operatorer för att göra klassen användbar och transparent. Klassen Vector representerar en matematisk vektor i rymdgeometri. Den innehåller x-, y- och z-koordinater samt metoder för att accessera dessa. En vektor definierar således en viss riktning och har en viss längd. Alla vektorer antas starta från origo, d.v.s. punkten (0, 0, 0).
Vi får en första definition av klassen Vector enligt följande:
#ifndef VECTOR_H #define VECTOR_H #include <iostream> #include <math.h> class Vector { public: // konstruktorer Vector (); Vector (const Vector & V); Vector (const float X, const float Y, const float Z); // accessera individuella komponenter void setX (const float X) { m_X = X; }; void setY (const float Y) { m_Y = Y; }; void setZ (const float Z) { m_Z = Z; }; float x () const { return m_X; }; float y () const { return m_Y; }; float z () const { return m_Z; }; // get the length of the vector float length () const; private: // x, y och z-komponenterna float m_X; float m_Y; float m_Z; }; #endif // VECTOR_H |
Koden ovan finns i en headerfil Vector1.h. Implementationen av metoderna finns i filen Vector1.cpp. Den ser i grundutförande ut på följande sätt:
#include "Vector1.h" Vector::Vector () { // nollställ alla medlemmar m_X = 0; m_Y = 0; m_Z = 0; } // copy-konstruktor Vector::Vector (const Vector & V) { // kopiera data från 'V' m_X = V.m_X; m_Y = V.m_Y; m_Z = V.m_Z; } // skapa från separata värden Vector::Vector (const float X, const float Y, const float Z) { // spara värden i medlemmar m_X = X; m_Y = Y; m_Z = Z; } // beräkna längden av vektorn float Vector::length () const { // använd Pythagoras return sqrt ( m_X * m_X + m_Y * m_Y + m_Z * m_Z ); } |
Senare då vi fyller på nya metoder skrivs inte båda filerna ut i sin helhet, utan endast prototypen på den nya (eller ändrade) metoden, samt implementationen om en dylik finns. Dessa skall då placeras i header- respektive implementationsfilen på korrekt plats. Korrekt plats i headerfilen är i klassens public:-avsnitt. Den kompletta klassen när den är färdig finns i Appendix C.
Förutgående | Hem | Nästa |
Hierarkier med exceptions | Överlagring av operatorn + |