overload operator c++ operator-overloading

overload - operator[] c++



diferencia entre operador global y operador miembro (5)

Aquí hay un ejemplo real donde la diferencia no es obvia:

class Base { public: bool operator==( const Base& other ) const { return true; } }; class Derived : public Base { public: bool operator==( const Derived& other ) const { return true; } }; Base() == Derived(); // works Derived() == Base(); // error

Esto se debe a que la primera forma utiliza el operador de igualdad de la clase base, que puede convertir su lado derecho en Base . Pero el operador de igualdad de clase derivado no puede hacer lo contrario, de ahí el error.

Si el operador de la clase base fuera declarado como una función global en su lugar, ambos ejemplos funcionarían (no tener un operador de igualdad en la clase derivada también solucionaría el problema, pero a veces es necesario).

¿Hay alguna diferencia entre definir un operador global que toma dos referencias para una clase y definir un operador miembro que toma solo el operando correcto?

Global:

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

Miembro:

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


Hay al menos una diferencia. Un operador miembro está sujeto a modificadores de acceso y puede ser público, protegido o privado. Una variable miembro global no está sujeta a restricciones de modificador de acceso.

Esto es particularmente útil cuando desea deshabilitar ciertos operadores como asignación

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

Puede lograr el mismo efecto teniendo un operador global declarado solo. Pero daría como resultado un error de enlace frente a un error de compilación (nipick: sí, se produciría un error de enlace dentro de Foo)


Para resumir a la respuesta de Codebender:

Los operadores miembros no son simétricos. El compilador no puede realizar el mismo número de operaciones con los operadores del lado izquierdo y derecho.

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; }

En el código anterior no se compilará si el operador es una función miembro mientras funcione como se espera si el operador es una función gratuita.

En general, un patrón común es implementar los operadores que deben ser funciones miembro como miembros y el resto como funciones gratuitas que delegan en los operadores miembros:

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; }


Su opción más inteligente es hacer que sea una función amiga .

Como menciona JaredPar, la implementación global no puede acceder a miembros protegidos y privados de la clase, pero también hay un problema con la función miembro.

C ++ permitirá conversiones implícitas de los parámetros de la función, pero no una conversión implícita de this .

Si existen tipos que se pueden convertir a su clase X:

class Y { public: operator X(); // Y objects may be converted to X }; X x1, x2; Y y1, y2;

Solo algunas de las siguientes expresiones se compilarán con una función miembro.

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

La solución, para obtener lo mejor de ambos mundos, es implementar esto como un amigo:

class X { int value; public: friend bool operator==( X& left, X& right ) { return left.value == right.value; }; };


Una razón para usar operadores que no son miembros (generalmente declarados como amigos) es porque el lado izquierdo es el que hace la operación. Obj::operator+ está bien para:

obj + 2

pero para:

2 + obj

no funcionará Para esto, necesitas algo como:

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) { ... }