How does "this" cascade mode work?

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 can these function calls be combined together? I do not understand why this works.

+6
source share
7 answers

Each of the t methods returns a reference in t. A link is an alias. So if you did

  Time t; Time& tAgain = t; tAgain.setMinute( 30 ); 

tAgain.setMinute also changes the time t.

Now extrapolate this simple cascading example. Each method t returns a reference to itself

  Time &Time::setSecond( int s ) { second = ( s >= 0 && s < 60 ) ? s : 0; return *this; } 

So in the expression:

  t.setHour( 18 ).setMinute( 30 ) 

t.setHour( 18 ) calls setHour on t, then returns a reference to t. In this case, the link is temporary. So you can think of it as if the above line changed to the following when evaluating setHour:

  tAgain.setMinute(30); 

t.setHour returned a link - similar to our tAgain above. Just an alias for himself.

+5
source

The reason this works correctly is that when called

 t.setHour( 18 ) 

The return value is a Time& , a reference to a Time object. More importantly, it is defined as

 Time &Time::setHour( int h ) { hour = ( h >= 0 && h < 24 ) ? h : 0; return *this; // <--- right here } 

Inside a member function, this is a pointer to the object that the call was made to, and *this is a reference to the object that the call was made to (the recipient object). This means that when you call setHour , the function sets the hour to time, and then returns a reference to the Time object that you made the call to. Thus, t.setHour( 18 ) sets the hour and then returns a reference to the recipient object. So you can write

 t.setHour( 18 ).setMinute( 30 ).setSecond( 22 ); 

as it is interpreted as

 ((t.setHour( 18 )).setMinute( 30 )).setSecond( 22 ); 

and in each case, the function returns a reference to t .

More generally, whenever a function returns a link and this *this link, any operation performed on the return value of a function is indistinguishable from operations that you perform on the object itself.

Hope this helps!

+14
source

Due to the fact that each function returns a reference to the object of the object (Return * this).

This basically means that every time a function is called, it makes the appropriate changes, and then passes the entire object back as a reference. Then you can make calls on this returned object.

It can also be written as follows:

  Time t; Time& t1 = t.setHour( 18 ); // t1 will refer to the same object as t. Time& t2 = t1.setMinute( 30 ); // t2 will refer to the same object as t1 and t. Time& t3 = t2.setSecond( 22 ); // t3 will refer to the same object as t2, t1 and t. 

This can facilitate understanding of what is happening.

+5
source

This is similar to overloading stream statements.

 ostream& operator<<(ostream& s, const T& val) { s << val; return s; } 

You do this because you are modifying the stream and returning it so that it can be used on the next cascade call, if necessary. It continues to receive the transmission by reference, so it can continue to move to the next segment of the expression.

Here's how:

 std::cerr << 1 << 2 << 3 << std::endl; 

works!:)

+3
source

This method is called a chain of methods . In the example you specified, all methods return the same object (this), so they all affect the same object. This is not uncommon, but it is useful to know that it is not necessary; some or all of the methods in the chain may return different objects. For example, you may also have methods such as:

 Date Time::date() const; String Date::dayOfWeek() const; 

in this case you could say:

 Time t; String day = t.date().dayOfWeek(); 

to get the name of the day of the week. In this case, t.date() returns a Date object, which in turn is used to call dayOfWeek() .

+1
source

This can help if you think that statements are resolved one step at a time.

Take for example the following:

 x = 1 + 2 * 3 - 4; x = 1 + 6 - 4; x = 7 - 4; x = 3; 

C ++ does the same with function calls and everything else that you do inside the statement, solving each element inside in order of priority of the statement. Thus, you can think that your example is solved in the same way:

 t.setHour( 18 ).setMinute( 30 ).setSecond( 22 ); t.setMinute( 30 ).setSecond( 22 ); // hour is now set to 18 t.setSecond( 22 ); // minute is now set to 30 t; // seconds now set to 22 

If you returned this instead of *this and thus indicating pointers instead of links, you will get the same effect, except that you replaced . to -> (as an example, you're doing it right using links). Similarly, if you returned a pointer or a link to another object, you can do the same with that. For example, let's say you have a function that returns a Time object.

 class Time{ public: int getSeconds(){ return seconds; }; int seconds; }; Time getCurrentTime(){ Time time = doSomethingThatGetsTheTime(); return time; }; int seconds = getCurrentTime().getSeconds(); 

You get seconds without having to split the statement into two different statements or make a temporary variable to hold the returned time object.

This C ++ question : Using '.' the operator for expressions and function calls gets a little deeper if you want to read.

+1
source

because when a function is executed and returned, it returns a reference to itself, so it can call functions .

+1
source

Source: https://habr.com/ru/post/896252/


All Articles