2009-07-17 17 views
30

Czy istnieje różnica między definiowaniem operatora globalnego, który pobiera dwa odwołania do klasy i definiującym operatora składowego, który przyjmuje tylko prawy operand?Różnica między operatorem globalnym a operatorem członkowskim

Globalny:

class X 
{ 
public: 
    int value; 
}; 

bool operator==(X& left, X& right) 
{ 
    return left.value == right.value; 
}; 

użytkownika:

class X 
{ 
    int value; 
    bool operator==(X& right) 
    { 
     return value == right.value; 
    }; 
} 
+2

Jest to dobra praktyka, aby zadeklarować argumenty nie tylko odniesienie, ale także const, ilekroć jesteś pewien, że możesz. Operatory porównania mogą być stałe i na pewno przyjmować odwołania do stałych. (Jeśli nic innego, to jest obiecujące dla kompilatora, który pozwala mu robić więcej optymalizacji.) –

Odpowiedz

39

Jednym z powodów używania operatorów nie będących członkami (zwykle deklarowanych jako przyjaciele) jest to, że lewy strona ręczna to ta, która wykonuje operację. Obj::operator+ jest w porządku:

obj + 2 

ale dla:

2 + obj 

to nie będzie działać. Do tego trzeba coś takiego:

class Obj 
{ 
    friend Obj operator+(const Obj& lhs, int i); 
    friend Obj operator+(int i, const Obj& rhs); 
}; 

Obj operator+(const Obj& lhs, int i) { ... } 
Obj operator+(int i, const Obj& rhs) { ... } 
5

Istnieje co najmniej jedna różnica. Operator członkowski podlega modyfikatorom dostępu i może być publiczny, chroniony lub prywatny. Globalna zmienna składowa nie podlega ograniczeniom modyfikatorów dostępu.

Jest to szczególnie przydatne, gdy chcesz wyłączyć niektóre podmioty jak przypisanie

class Foo { 
    ... 
private: 
    Foo& operator=(const Foo&); 
}; 

Można osiągnąć ten sam efekt przez posiadające tylko zadeklarowane operatorem globalnej. Ale spowodowałoby to błąd łącza w porównaniu do błędu kompilacji (nipick: tak, spowodowałoby to błąd łącza w obrębie Foo).

+0

Zadeklarowany globalny operator nie będzie łączyć (tj. Żadnego programu), podczas gdy prywatny operator będzie. Tylko nielegalne użycie członka prywatnego spowoduje błąd kompilacji. Poprawny? –

6

Twój najmądrzejszym rozwiązaniem jest stworzenie funkcji przyjaciela.

Jak wspomina JaredPar, implementacja globalna nie może uzyskać dostępu do chronionych i prywatnych członków klasy, ale istnieje również problem z funkcją członka.

C++ zezwala na niejawne konwersje parametrów funkcji, ale nie na niejawną konwersję wartości .

Jeśli istnieją typy, które mogą być konwertowane do klasy X:

class Y 
{ 
public: 
    operator X(); // Y objects may be converted to X 
}; 


X x1, x2; 
Y y1, y2; 

tylko niektóre z następujących wyrażeń zostanie skompilowany z funkcji członka.

x1 == x2; // Compiles with both implementations 
x1 == y1; // Compiles with both implementations 
y1 == x1; // ERROR! Member function can't convert this to type X 
y1 == y2; // ERROR! Member function can't convert this to type X 

rozwiązanie, aby uzyskać najlepsze z obu światów, jest wdrożenie tego jako znajomego:

class X 
{ 
    int value; 

public: 

    friend bool operator==(X& left, X& right) 
    { 
     return left.value == right.value; 
    }; 
}; 
+1

To nie jest błąd, to funkcja;) Nienawidzę niejawnych konwersji ... –

6

Reasumując do odpowiedzi przez Codebender:

operatorzy państwa nie są symetryczny. Kompilator nie może wykonać tej samej liczby operacji z operatorami po lewej i prawej stronie.

struct Example 
{ 
    Example(int value = 0) : value(value) {} 
    int value; 

    Example operator+(Example const & rhs); // option 1 
}; 
Example operator+(Example const & lhs, Example const & rhs); // option 2 
int main() 
{ 
    Example a(10); 
    Example b = 10 + a; 
} 

W powyższym kodzie nie można skompilować, jeśli operator jest funkcją składową, gdy będzie działał zgodnie z oczekiwaniami, jeśli operator jest wolną funkcją.

W ogólnym wspólnego wzorca wdraża operatorów, które muszą być funkcje członka, jak członków, a reszta jako wolne funkcje delegata na operatorów członkowskich:

class X 
{ 
public: 
    X& operator+=(X const & rhs); 
}; 
X operator+(X lhs, X const & rhs) 
{ 
    lhs += rhs; // lhs was passed by value so it is a copy 
    return lhs; 
} 
Powiązane problemy