[ Team LiB ] Previous Section Next Section

Gotcha #24: Operator -> Subtleties

The predefined -> operator is binary: the left operand is a pointer, and the right operand is the name of a class member. Overloaded operator -> is a unary member function!

gotcha24/ptr.h



class Ptr { 


 public:


   Ptr( T *init );


   T *operator ->();


   // . . .


 private:


   T *tp_;


};


An invocation of overloaded -> must return something that may then be used with an -> operator to access a member:

gotcha24/ptr.cpp



Ptr p( new T ); 


p->f(); // p.operator ->()->f()!


One way to look at it is that the -> token is not "consumed" by an overloaded operator -> but is instead retained for eventual use as the predefined -> operator. Typically, some additional semantics are attached to the overloaded -> to create a "smart pointer" type:

gotcha24/ptr.cpp



T *Ptr::operator ->() { 


   if( today() == TUESDAY )


       abort();


   else


       return tp_;


}


We mentioned that an overloaded operator -> must return "something" that may be then used to access a member. That something doesn't have to be a predefined pointer. It could be a class object that itself overloads operator ->:

gotcha24/ptr.h



class AugPtr { 


 public:


   AugPtr( T *init ) : p_( init ) {}


   Ptr &operator ->();


   // . . .


 private:


   Ptr p_;


};


gotcha24/ptr.cpp



Ptr &AugPtr::operator ->() { 


   if( today() == FRIDAY )


     cout << '\a' << flush;


   return p_;


}


This allows the cascading of smart pointer responsibilities:

gotcha24/ptr.cpp



AugPtr ap( new T ); 


ap->f(); // ap.operator ->().operator ->()->f()!


Note that the sequence of operator -> activations is always determined statically by the type of the object that contains the operator -> definition, and the sequence of operator -> member function calls always terminates in a call that returns a predefined pointer to class. For example, applying the -> operator to an AugPtr will always result in the sequence of calls AugPtr::operator -> followed by Ptr::operator ->, followed by a predefined -> operator applied to a T * pointer. (See Gotcha #83 for a more realistic example of the use of operator ->.)

    [ Team LiB ] Previous Section Next Section