I have the following class interface:
class Time
{
public:
Time( int = 0, int = 0, int = 0 );
Time &setHour( int );
Time &setMinute( int );
Time &setSecond( int );
private:
int hour;
int minute;
int second;
};
The implementation is here:
Time &Time::setHour( int h )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
return *this;
}
Time &Time::setMinute( int m )
{
minute = ( m >= 0 && m < 60 ) ? m : 0;
return *this;
}
Time &Time::setSecond( int s )
{
second = ( s >= 0 && s < 60 ) ? s : 0;
return *this;
}
In my main .cpp file, I have this code:
int main()
{
Time t;
t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
return 0;
}
How is it possible to chain these function calls together? I don't understand why this works.
Each of t's methods return a reference to t. A reference is an alias. So if you did
tAgain.setMinute
also alters t's time.Now extrapolate that simple example to cascading. Each method of t returns a reference to itself
So in the expression:
t.setHour( 18 )
calls setHour on t, then returns a reference to t. In this case the reference is temporary. So you can think of it as if the above line changed to the following on evaluating setHour:t.setHour returned a reference -- similar to our tAgain above. Just an alias for t itself.
This is similar to overloading stream operators.
You do this because you modify the stream and return it so it can be used in the next cascading call if desired. It keeps getting passed by reference so it can keep going into the next expression segment.
Thats how:
works! :)
It might help if you think of the statements being solved one step at a time.
Take the following for instance:
C++ does the same with function calls and everything else you do within a statement, solving each element inside in the order of operator precedence. So you can think of your example as being solved in the same way:
If you returned
this
instead of*this
, and thus returning pointers instead of references, you would get the same effect except you would replace the.
with->
(just as an example, you're doing it right by using references). In the same way, if you returned an pointer or reference to a different object, you could do the same thing with that. For instance, let's say you have a function that returns aTime
object.You get the seconds without having to split the statement into two different statements or making a temporary variable to hold the returned Time object.
This question C++: Using '.' operator on expressions and function calls goes a little more indepth if you wanted to read.
Due to the fact that each function returns a reference to the this object object (The return *this).
Basically this means that every time the function is called it make the relevant changes and then passes the entire object back out as a reference. It is then possible to make calls on that returned object.
It could also be written as follows:
That may make it easier to understand what is going on.
because when a function is executed and returns then it returns reference to itself so again it can call
functions
.The reason that this works correctly is that when you call
The return value is a
Time&
, a reference to aTime
object. More importantly, it's defined asInside of a member function,
this
is a pointer to the object on which the call was made, and*this
is a reference to the object on which the call was made (the receiver object). This means that when you callsetHour
, the function sets the hour on the time, then returns a reference to theTime
object on which you made the call. Thust.setHour( 18 )
both sets the hour and then returns a reference to the receiver object. That way, you can writebecause it's interpreted as
and in each case the function returns a reference to
t
.More generally, any time a function returns a reference and that reference is
*this
, any operation you perform on the return value of the function is indistinguishable from operations that you would perform on the object itself.Hope this helps!