2011-02-07 8 views
6

Duplicar posible:
Overloading operator ->¿Está el operador-> "encadenado" para los punteros?

Hola,

he visto que operator->() es encadenado (re-aplicado) después de que se evalúa, por ejemplo:

struct Bar 
{ 
    Bar() : m_str("Hello world!") {} 
    const string* operator->() const { return &m_str; } 
    string m_str; 
}; 

struct Foo 
{ 
    const Bar& operator->() const { return m_bar; } 
    Bar m_bar; 
}; 

int main() 
{ 
    Foo f; 
    cout << f->c_str() << endl; 
    return 0; 
} 

funciona bastante bien, lo que requiere tres operator->() para ser evaluado - Foo::operator->(), Bar::operator->() y resolución de puntero regular.

Pero no funcionará con punteros en el medio - si Foo::operator->() devuelve el puntero a la barra en lugar de referencia, no se compilará. Lo mismo ocurre con auto_ptr<auto_ptr<string>> por ejemplo.

¿Es específico para operator->() no sobrecargado por lo que solo se aplica una vez y no causa encadenamiento? ¿Es posible hacer que el siguiente código funcione sin usar (*ptr2)-> ...?

int main() 
{ 
    string s = "Hello world"; 
    auto_ptr<string> ptr1(&s); 
    auto_ptr<auto_ptr<string> > ptr2(&ptr1); 
    cout << ptr1->c_str() << endl; // fine 
    cout << ptr2->c_str() << endl; // breaks compilation 
} 

Gracias!

+0

Duplicado de [Operador de sobrecarga ->] (http://stackoverflow.com/questions/4896238/overloading-operator) [La respuesta de AndreyT explica el comportamiento de 'operator->' y cómo se produce el "encadenamiento".] –

+1

@James Me gustaría mantener esto abierto ya que la redacción de la pregunta es diferente. Puede ayudar a otras personas a encontrar esa respuesta. –

+2

@Judge: una pregunta cerrada no se elimina automáticamente, y una pregunta bien hecha como esta no se eliminará; la pregunta seguirá existiendo y podrá buscarse. –

Respuesta

12

C++ 98 estándar §13.5.6/1 "acceso miembro de la Clase":

Una expresión x->m se interpreta como (x.operator->())->m para un objeto de clase x de tipo T si T::operator-> existe y si el operador es seleccionado en la mejor función de coincidencia por el mecanismo de resolución de sobrecarga (13.3).

Lo que esto significa en la práctica es que cuando x es un puntero, usted no consigue encadenar ’ t; luego obtiene el operator-> incorporado (es decir, x->m con x, un puntero se traduce a (*x).m).

Pero cuando x es un objeto del tipo de clase T, puede obtener el efecto de encadenamiento.Porque entonces la interpretación como (x.operator->())->m puede ser que (x.operator->()) sea un objeto de alguna clase, digamos clase U. De ahí que el segundo -> se pueda resolver como U::operator->, y así sucesivamente, si el resultado de eso nuevamente es un tipo de clase objeto & hellip;

Como, en su caso, Foo::operator-> produce (una referencia a) un objeto de la clase Bar, que define un operator->.

Pero cuando operator-> devuelve un puntero, como p. std::auto_ptr<T>::operator->, entonces es solo el operator-> incorporado que se usa.

De pasada, el encadenamiento puede se puede utilizar para evitar prácticamente que alguien use delete incorrectamente. std::auto_ptr no hace eso. Y yo ’ nunca lo he visto hecho.

Pero hubo una vez un largo hilo de discusión en [comp.lang.C++. Moderado] acerca de cómo evitar delete inadvertido del puntero sin formato administrado por un puntero inteligente, y esta fue una posibilidad que se discutió.

Cheers & hth.

0

No, no es posible que funcione. Si pudiera sobrecargar operator -> para string *, podría hacerlo funcionar. Pero operator -> ya tiene una definición para todos los tipos de punteros. Por lo tanto, al igual que no puede sobrecargar + para los tipos numéricos primitivos, no puede sobrecargar operator -> para ningún tipo de puntero.

E incluso si pudiera, ¿cómo podría saber el compilador cuándo debería finalizar la recursión?

3

El motivo por el que funciona su primer ejemplo es porque devolvió una referencia en lugar de un puntero. Ese operador normalmente no sería válido, excepto en el caso de que esté sobrecargado. Por lo tanto, el compilador debe ejecutar las funciones sobrecargadas en la cadena. Sin embargo, en el caso de auto_ptr, en realidad se le devuelve un puntero real y se invoca el valor predeterminado operator -> para los punteros normales. Para obtener más información, consulte la pregunta Overloading operator ->.

+0

Gracias por la respuesta. Estaba buscando un enfoque para simplificar el código para iterar vector > y cosas similares. Parece que la única opción es especializar el iterador del vector (cualquier contenedor) para shared_ptr (algunos otros ptr inteligentes), lo que no es aceptable. – nyrl

Cuestiones relacionadas