2011-02-04 27 views
17

Aquí está mi ejemplo de código:sobrecarga de operadores ->

class X 
{ 
public: 
     void f() {} 
}; 

class Y : public X 
{ 
public: 
     X& operator->() { return *this; } 
     void f() {} 
}; 

int main() 
{ 
     Y t; 
     t.operator->().f(); // OK 
     t->f(); // error C2819: type 'X' does not have an overloaded member 'operator ->' 
       // error C2232: '->Y::f' : left operand has 'class' type, use '.' 
} 

Por qué el compilador está tratando de "mover la responsabilidad" por operator-> de Y a X? Cuando implemente X :: OP> entonces no puedo volver allí X - error de compilación dice "bucle infinito", mientras que devolver algunos de Z X :: OP> de nuevo dice que Z no tiene del operador>, yendo así más alto y más alto en jerarquía.

Puede alguien explicar este comportamiento interesante? :)

Respuesta

18

El problema es que operator -> se supone que devolver un puntero, no una referencia. La idea es que operator -> debería devolver un puntero al objeto real que debe tener el puntero que se le aplica. Por ejemplo, para una clase con un operator -> sobrecargada, el código

myClass->myValue; 

se traduce en

(myClass.operator->())->myValue; 

El problema con el código es que operator -> devuelve una referencia, por lo que escribir

myClass.operator->().f(); 

es perfectamente legal porque estás invocando expresamente el operador, pero escribir

myClass->f(); 

es ilegal, ya que el compilador está tratando de ampliarlo a

myClass.operator->()->f(); 

y el tipo de retorno de operator-> no es un puntero.

Para solucionar este problema, cambiar su código para que regrese un puntero en operator ->. Si desea sobrecargar un operador para devolver una referencia, sobrecargar operator *; las referencias al puntero deberían producir referencias.

+9

yo no diría que es supone para devolver un puntero, al igual que todo lo que devuelve las necesidades del operador para apoyar '>'. – GManNickG

+1

@ GMan- Buen punto. Me iba por la simplicidad aquí, pero estás en lo cierto. Hay algunos trucos realmente divertidos que puede realizar con punteros inteligentes que se basan en esta técnica. – templatetypedef

+0

@GMan: dado que estos tipos se denominan colectivamente * punteros inteligentes *, no creo que templatetypedef esté equivocado al usar el término * puntero *, simplemente lo está usando en un sentido general. –

2

La sintaxis es incorrecta, debería ser:

T-> T2

T2* T::operator ->();​ 

Mira el artículo de wikipedia: Operators in C and C++

Si desea sobrecargar, debe utilizar la sintaxis correcta para el operador sobrecargado

19

Porque así es como overlo aded -> funciona en C++.

Cuando se utiliza el sobrecargado ->, la expresión a->b se traduce en a.operator->()->b. Esto significa que su operador sobrecargado -> debe devolver algo que sea compatible con otra aplicación del operador ->. Por esta razón, una sola invocación de -> sobrecargado podría convertirse en una larga cadena de invocaciones de -> s sobrecargadas hasta que llegue a una aplicación de ->, que finaliza la cadena.

En su caso debe devolver desde su -> sobrecargado, no X&.

1

es probable que desee:

class Y : public X 
{ 
public: 
     X* operator->() { return this; } 
     void f() {} 
};