2012-05-05 7 views
7

Se dice que el operador de flecha se aplica recursivamente. Pero cuando trato de ejecutar el código siguiente, se imprime un galimatías cuando se supone para imprimir 4.aplicación recursiva de operador->

class dummy 
{ 
public: 
    int *p; 

    int operator->() 
    { 
     return 4; 
    } 
}; 

class screen 
{ 
public: 
    dummy *p; 

    screen(dummy *pp): p(pp){} 
    dummy* operator->() 
    { 
     return p; 
    } 
}; 

int main() 
{ 
    dummy *d = new dummy; 
    screen s(d); 
    cout<<s->p; 
    delete d; 
} 
+6

¿Dónde se dice que se "aplica recursivamente"? –

+0

No, no estoy de acuerdo con que su ejemplo funcione como se esperaba, el -> opertor es solo una llamada de función en esencia, ¿por qué debería profundizarse? Si lo hiciera así, ¿cómo controlaría a qué nivel detener la desreferenciación y haría que la herencia y el polimorfismo fueran aún más complicados de lo que ya es – EdChum

+2

C++ Primer, cuarta edición Por Stanley B. Lippman, sección 14.6 último párrafo. – user1232138

Respuesta

10

lo que Stanley entiende por “recursivo” es sólo que el operador se aplica a cada objeto devuelto hasta el el tipo devuelto es un puntero.

Lo que sucede aquí en el primer intento: screen::operator -> devuelve un puntero. Por lo tanto, esta es la última llamada a un operator -> que intenta el compilador. A continuación, resuelve el lado derecho del operador (p) buscando un miembro en el tipo de puntaje devuelto (dummy) con ese nombre.

Esencialmente, cada vez que el compilador encuentra la sintaxis aᵢ->b en el código, que, esencialmente, se aplica el siguiente algoritmo:

  1. Es aᵢ del tipo de puntero? De ser así, resuelva el miembro b de *aᵢ y llame al (*aᵢ).b.
  2. lo demás, tratar de resolver aᵢ::operator ->
    1. En caso de éxito, establecer aᵢ₊₁ = aᵢ::operator ->(). Ir a 1.
    2. En caso de error, emita un error de compilación.

estoy en apuros para llegar a un pequeño ejemplo, donde un significativo cadena de invocaciones operator -> siquiera tiene sentido. Probablemente, el único uso real sea cuando escribe una clase de puntero inteligente.

Sin embargo, el siguiente ejemplo de juguete al menos compila y arroja un número. Pero no aconsejaría realmente escribir dicho código. Rompe la encapsulación y hace llorar a los gatitos.

#include <iostream> 

struct size { 
    int width; 
    int height; 
    size() : width(640), height(480) { } 
}; 

struct metrics { 
    size s; 
    size const* operator ->() const { 
     return &s; 
    } 
}; 

struct screen { 
    metrics m; 
    metrics operator ->() const { 
     return m; 
    } 
}; 

int main() { 
    screen s; 
    std::cout << s->width << "\n"; 
} 
+0

tal vez mi concepto sería más claro si pudiera decirme cómo puedo imprimir 4 en este ejemplo. – user1232138

+0

@ user1232138 No puede. La última llamada en la cadena de 'operator ->' ** debe ** devolver un puntero. –

+0

@ user1232138 Sin embargo, consulte mi actualización para ver un ejemplo de trabajo. Tenga en cuenta que lo que dije antes aún se mantiene. Debe devolver un puntero, por lo tanto, si desea recuperar un valor entero, debe estar almacenado en la expresión del lado derecho del operador (en este caso, 'size :: width'). –

0

El acuerdo es una vez screen::operator->() devuelve un puntero (dummy*) la recursividad se detiene porque incorporado (por defecto) en -> utilizados en ese puntero. Si quieres recursividad debe volver dummy o dummy& de screen::operator->()

1

C++ Primer (5ª edición) la formula de la siguiente manera en la página 570:

El operador flecha nunca pierde su significado fundamental de acceso miembro. Cuando sobrecargamos la flecha, cambiamos el objeto desde el cual la flecha obtiene el miembro especificado. No podemos cambiar el hecho de que la flecha atrapa a un miembro.