2010-06-26 19 views
7

Sé que puedo responder esta pregunta fácilmente generando el código y ver si se compila. Pero como no pude encontrar una pregunta similar, pensé que valía la pena compartirla. Supongamos que estoy sobrecargando el operador + de MyClass. ¿Puedo sobrecargarlo varias veces? Diferente sobrecarga para diferentes tipos. De esta manera:C++ múltiples sobrecargas de operador para el mismo operador

class MyClass{ 
... 
inline const MyClass operator+(const MyClass &addend) const { 
    cout<<"Adding MyClass+MyClass"<<endl; 
    ...//Code for adding MyClass with MyClass 
} 
inline const MyClass operator+(const int &addend) const { 
    cout<<"Adding MyClass+int"<<endl; 
    ...//Code for adding MyClass with int 
} 
... 
}; 
int main(){ 
    MyClass c1; 
    MyClass c2; 
    MyClass c3 = c1 + c2; 
    MyClass c4 = c1 + 5; 
} 
/*Output should be: 
    Adding MyClass+MyClass 
    Adding MyClass+in*/ 

La razón por la que quiero hacer esto es que estoy construyendo una clase que yo quiero estar tan optimizado como sea posible. El desempeño es la mayor preocupación para mí aquí. Así que fundir y usar la caja del interruptor dentro del operador + función sobrecargada no es una opción. Si lo nota, hice las dos sobrecargas en línea. Supongamos por un segundo que el compilador en verdad indica mis sobrecargas, luego está predeterminado en tiempo de compilación qué código se ejecutará, y guardo la llamada a una función (al subrayar) + un escenario complicado de caso de conmutación (en realidad, habrá Más de 5 sobrecargas para el operador +), pero todavía puedo escribir código de lectura fácil usando operadores aritméticos básicos. Entonces, ¿obtendré el comportamiento deseado?

+0

Si le preocupa el rendimiento, desde un punto de vista de clase, devolver '* this' a' const Myclass & 'será mejor. Ahora, desde el punto de vista del usuario (a menos que esté compilando en C++ 0x), debe usar '+ =' en lugar de '+' y '=' para evitar temporales inútiles que quizás no sean optimizados por un crappy compiladores. – paercebal

+0

No tengo idea de por qué esto fue votado negativamente. Es una pregunta perfectamente válida.(El hecho de que encuentre esta información en otra parte no es razón para no encontrar la respuesta aquí también.) – sbi

+3

@paercebal: Está implementando la suma a, no un incremento. Si él estaba implementando 'operator + =', entonces devolver una referencia estaría bien (después de modificar el estado interno), pero 'a + b' no pretende modificar el' a', sino que produce un tercer valor que difiere de ambos 'a' y' b'. –

Respuesta

8

La forma canónica de implementar operator+() es una función gratuita basada en operator+=(), que los usuarios esperarán cuando tenga +. += cambia su argumento de la izquierda y, por lo tanto, debe ser un miembro. El + trata sus argumentos de forma simétrica y, por lo tanto, debe ser una función libre.

Algo como esto debería hacer:

//Beware, brain-compiled code ahead! 
class MyClass { 
public: 
    MyClass& operator+=(const MyClass &rhs) const 
    { 
     // code for adding MyClass to MyClass 
     return *this; 
    } 
    MyClass& operator+=(int rhs) const 
    { 
     // code for adding int to MyClass 
     return *this; 
    } 
}; 


inline MyClass operator+(MyClass lhs, const MyClass& rhs) { 
    lhs += rhs; 
    return lhs; 
} 
inline MyClass operator+(MyClass lhs, int rhs) { 
    lhs += rhs; 
    return lhs; 
} 
// maybe you need this one, too 
inline MyClass operator+(int lhs, const MyClass& rhs) { 
    return rhs + lhs; // addition should be commutative 
} 

(Tenga en cuenta que las funciones miembro definidas con su definición de clase son implícitamente inline Tenga en cuenta también, que dentro de MyClass, el prefijo MyClass:: o bien no es necesario o incluso mal..)

+1

+1 para la forma correcta. Sin embargo, probablemente usaría Boost.Operators para generar las funciones gratuitas de forma gratuita :) –

+0

qn muy básico: su definición para + requiere que lhs sea una constante, mientras que el código requiere que escriba lhs + = rhs. Parece que debes cambiar tu código o tu definición. ¿Estoy en lo cierto? – vad

+0

@Anon: Esa fue una gran propaganda mía. '' Fui a arreglarlo, y aproveché la oportunidad para agregar mi descargo de responsabilidad estándar. – sbi

9

Sí.


Estas funciones de operador son sólo funciones normales con los nombres especiales [email protected]. No hay restricción de que no puedan ser sobrecargados. De hecho, el operador << utilizado por iostream es un operador con múltiples sobrecargas.

+0

Me siento mal abarrotar tu respuesta con un comentario. Spot on. –

2

Sí, puede sobrecargar a los operadores de esta manera. Pero no estoy seguro de a qué "caja del interruptor" te refieres. Puede vivir con una sobrecarga si tiene un constructor de conversión

class MyClass{ 
... 
// code for creating a MyClass out of an int 
MyClass(int n) { ... } 
... 
inline const MyClass MyClass::operator+(const MyClass &addend) const { 
    cout<<"Adding MyClass+MyClass"<<endl; 
    ...//Code for adding MyClass with MyClass 
} 
... 
}; 

No se necesita ningún interruptor. Esto es elegible si "MyClass" representa lógicamente un número.

Observe que debe sobrecargar estos operadores por funciones que no son miembros. En su código 5 + c1 no funcionaría, porque no hay ningún operador que tome un int como lado izquierdo. El siguiente funcionaría

inline const MyClass operator+(const MyClass &lhs, const MyClass &rhs) { 
    // ... 
} 

Ahora bien, si se mantiene el constructor de conversión puede agregar el int por cada lado con una sobrecarga código mínimo.

+0

Johannes, ese constructor implícito de conversión podría no ser una buena idea. Por un lado, las conversiones IME implícitas suelen ser una mala idea tarde o temprano de todos modos, pero también porque eladidan quiere hacer esto porque "estoy construyendo una clase que quiero que esté lo más optimizada posible". En ese caso, las sobrecargas son mejores de todos modos. – sbi

+1

Ah, y copiando sin pensar 'inline blah MyClass ::' en 'MyClass' no te parece en absoluto. ':)' – sbi