2012-01-12 22 views
6

mi problema es simple. Tengo una plantilla de clase que contiene un puntero a un tipo asignado dinámicamente. Quiero sobrecargar el operador de direccionamiento indirecto de manera que al referirme a la instancia de la plantilla de clase con el operador -> me redireccionen como si usara el puntero que figuraba directamente.Sobrecarga del operador de direccionamiento indirecto en C++

template<class T> 
class MyClass 
{ 
    T *ptr; 
    ... 
    // created dynamic resource for ptr in the constructor 
}; 

Crear miclase de algún tipo:

MyClass<SomeObject> instance; 

Así que lo que quiero es en lugar de tener que escribir:

instance.ptr->someMemberMethod(); 

simplemente escribo:

intance->someMemberMethod(); 

Incluso Tú instance no es ap ointer se comporta como si fuera el puntero instance contiene. ¿Cómo salvar esa brecha al sobrecargar al operador?

+0

El moderno diseño C++ (Andrei Alexandrescu) tiene información muy buena sobre el tema si desea más profundidad. –

Respuesta

11

justo Usted puede sobrecargar operator-> y operator*:

template<class T> 
class MyClass 
{ 
    T* ptr; 

public: 
    T* operator->() { 
     return ptr; 
    } 

    // const version, returns a pointer-to-const instead of just a pointer to 
    // enforce the idea of the logical constness of this object 
    const T* operator->() const { 
     return ptr; 
    } 

    T& operator*() { 
     return *ptr; 
    } 

    // const version, returns a const reference instead of just a reference 
    // to enforce the idea of the logical constness of this object 
    const T& operator*() const { 
     return *ptr; 
    } 
}; 

Tenga en cuenta que, debido a una decisión de diseño por el creador de la lengua, no se puede sobrecargar el operador ..

Además, se podría pensar que habría operator* sobrecargar el operador de multiplicación en lugar del operador eliminar la referencia. Sin embargo, este no es el caso, porque el operador de multiplicación toma un solo argumento (mientras que el operador de desreferencia no toma argumentos), y debido a esto, el compilador puede decir cuál es cuál.

Por último, tenga en cuenta que operator-> devuelve un puntero pero operator* devuelve una referencia. Es fácil confundirlos accidentalmente.

+0

Buena respuesta. ¿Pero puedes decir la diferencia entre la versión const-versión y la no-const? ¿Cuándo usaría cualquiera de ellos? – SimpleGuy

+0

También por qué es necesario sobrecargar '->' y '*'. ¿Por qué simplemente sobrecargar '->' no es suficiente? – SimpleGuy

+0

@SimpleGuy Los usuarios de su clase generalmente esperan que 'foo-> bar' sea equivalente a' (* foo) .bar'. Tenerlos diferentes sorprenderá a muchas personas. – Bernard

5

sobrecarga del operador ->:

template <typename T> class MyClass 
{ 
    T * p; 
public: 
    T  * operator->()  { return p; } // #1 
    T const * operator->() const { return p; } 
}; 

Tenga en cuenta que ambos sobrecargas no mutan el objeto; sin embargo, decidimos hacer n. ° 1 no const, de modo que legaremos constness del objeto sobre el pointee. Esto a veces se llama "propagación de la consistencia profunda" o algo por el estilo. El lenguaje D lleva esto mucho más allá.

+0

"decidimos hacer # 1 no const" - al menos, podemos hacerlo si queremos. Los punteros inteligentes estándar no lo hacen, esencialmente por la misma razón que es posible modificar un objeto de tipo 'T' a través de' T * const'. Lo que haces depende de si 'instancia' es 'lógicamente' una referencia indirecta al otro objeto (en cuyo caso imitan punteros inteligentes estándar) o no (en cuyo caso, maldice Bjarne diciendo que no puede sobrecargar' operador'). –

+1

@SteveJessop: "Nosotros" como en "usted y yo, en este viaje hacia C++", en lugar de "nosotros los gobernantes actuales de toda opinión", supongo. Lo siento, viejos hábitos :-) –

3

El operador de acceso miembro puede ser sobrecargado para devolver un puntero al objeto de ser visitada:

T * operator->() {return ptr;} 
T const * operator->() const {return ptr;} 

También puede ser que desee el operador deferencia, para que se sienta aún más como un puntero; esto devuelve una referencia en su lugar:

T & operator*() {return *ptr;} 
T const & operator*() const {return *ptr;}