2013-03-15 11 views
15

Sto imparando C++ e ho creato due semplici applicazioni hello-world. In entrambi utilizzo il sovraccarico dell'operatore, ma qui è il problema. Sul primo, posso fornire due argomenti per sovraccaricare l'operatore, e va bene.Numero di argomenti nel sovraccarico dell'operatore in C++

Intestazione:

enum Element {a,b,c,d,e}; 
Element operator + (Element x, Element y); 
//more overloads for -, *,/here 

Fonte:

Element operator + (Element x, Element y) { 
    return ArrayOfElements[x][y]; 
} 

Ma nel mio secondo app (semplice calcolatore di numero complesso) - questo metodo non ha funzionato. Dopo googling e cercare di capire il motivo per cui, io alla fine con questo codice:

Intestazione:

struct Complex { 
     double Re; 
     double Im; 

     Complex (double R, double I) : Re(R), Im(I) { } 

     Complex operator + (Complex &Number); 
     //more overloads 
    }; 

Fonte:

Complex Complex::operator + (Complex &Number) 
    { 
     Complex tmp = Complex(0, 0); 
     tmp.Re = Re + Number.Re; 
     tmp.Im = Im + Number.Im; 
     return tmp; 
    } 

E 'ora di lavoro, ma voglio sapere , perché nel primo pezzo di codice mi è stato permesso di inserire due argomenti nell'overloading operator, ma con il secondo mi è stato dato il seguente errore?

complex.cpp:5:51: error: 'Complex Complex::operator+(Complex, Complex)' must take either zero or one argument 

E 'lo stesso ogni volta che uso le classi o no. Ho cercato attraverso molti documenti e il secondo modo sembra essere più corretto. Forse è a causa di diversi tipi di argomenti?

Entrambe le fonti sono compilate con i parametri -Wall -pedantic utilizzando g++, entrambi utilizzano le stesse librerie.

+5

Le funzioni membro hanno un argomento implicito 'this' –

risposta

24

Supponiamo di avere una classe come questa:

class Element { 
public: 
    Element(int value) : value(value) {} 
    int getValue() const { return value; } 
private: 
    int value; 
}; 

Ci sono quattro modi per definire un operatore binario, come +.

  1. Come funzione libera con accesso solo ai public membri della classe:

    // Left operand is 'a'; right is 'b'. 
    Element operator+(const Element& a, const Element& b) { 
        return Element(a.getValue() + b.getValue()); 
    } 
    

    e1 + e2 == operator+(e1, e2)

  2. Come una funzione membro, con accesso a tutti i membri della classe:

    class Element { 
    public: 
        // Left operand is 'this'; right is 'other'. 
        Element operator+(const Element& other) const { 
         return Element(value + other.value); 
        } 
        // ... 
    }; 
    

    e1 + e2 == e1.operator+(e2)

  3. Come funzione friend, con accesso a tutti i membri della classe:

    class Element { 
    public: 
        // Left operand is 'a'; right is 'b'. 
        friend Element operator+(const Element& a, const Element& b) { 
         return a.value + b.value; 
        } 
        // ... 
    }; 
    

    e1 + e2 == operator+(e1, e2)

  4. Come funzione friend definita all'esterno della classe corpo-identico comportamento a # 3:

    class Element { 
    public: 
        friend Element operator+(const Element&, const Element&); 
        // ... 
    }; 
    
    Element operator+(const Element& a, const Element& b) { 
        return a.value + b.value; 
    } 
    

    e1 + e2 == operator+(e1, e2)

+3

Se è una funzione membro, puoi fare 'Elemento (2) + 3' ma non' 2 + Elemento (3) '. – aschepler

+0

Non ho classi nel primo (solo nel secondo), ma grazie per l'ottima risposta! – Lemurr

1

Se si preferisce che operator+ prende entrambi gli operandi come argomenti espliciti, si deve essere definito come un libero (cioè non-membro) Funzione:

class Complex { 
    friend Complex operator+(const Complex& lhs, const Complex& rhs); 
} 

Complex operator+(const Complex& lhs, const Complex& rhs) { 
    ... 
} 

È hanno di utilizzare questo modulo se l'operando sinistro è di tipo primitivo, o di una classe che non controlli (e quindi non può aggiungere una funzione membro a).

+2

... e dovresti utilizzare questo modulo se potrebbero esserci conversioni implicite in' Complesso'. – aschepler

4

Poiché + è un operatore binario, se lo si sovraccarica in una struct/classe, è possibile fornire solo un altro operando, poiché il primo operando è implicitamente l'oggetto chiamante. Questo è il motivo per cui nel primo caso, hai due parametri poiché è al di fuori dell'ambito della tua classe/struct, mentre nel secondo caso è stato sovraccaricato come funzione membro.

1

Se funzione sovraccaricata è una funzione membro alla classe, la passiamo solo argomento, e c'è un parametro nascosto (questo puntatore) che punta a altro oggetto richiesto per eseguire un'operazione binaria come '+ '. questo puntatore punta a uno degli operandi e chiama la funzione sovraccaricata; mentre un altro operando viene passato come argomento. Esempio:

class ExampleClass 
{ 
public: 
    int x; 
    //a this pointer will be passed to this function 
    ExampleClass& operator+(const ExampleClass& o){ return x+o.x; } 
}; 



ExampleClass obj1, obj2, obj; 
obj = obj1 + obj2; //the overloaded function is called as obj1.operator+(obj2) internally 
        //this pointer is passed to the function 

Quando la funzione di sovraccarico non è una funzione di membro (o una funzione libera o una funzione amico), quindi non abbiamo il puntatore questo fornito alla funzione di sovraccarico. In questo caso, il compilatore si aspetta due argomenti per la funzione che vengono utilizzati come operandi.

class ExampleClass 
{ 
    public: 
     int x; 
     //this pointer will not be passed to this function 
     friend ExampleClass& operator+(const ExampleClass& o1, const ExampleClass& o2){ return o1.x+o2.x; } 
}; 



obj = obj1 + obj2; //the overloaded function is called as operator+(obj1, obj2) internally 
0

e1 + e2 == e1.operator + (e2) significa e1 è un oggetto ed esercente + è un membro e e2 è come variabile .basicaly oops ci permette di fare solo scrivere e1 + e2 comprendere compilatore automaticamente come e1.operator + (e1)