Как работает каскадирование" это"?

у меня есть следующий класс интерфейс:

  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; 
  }; 

реализация здесь:

  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; 
   }

в моем основном .cpp файл, у меня есть этот код:

int main()
{
    Time t;     
    t.setHour( 18 ).setMinute( 30 ).setSecond( 22 );
    return 0;
}

как можно связать эти вызовы функций вместе? Я не понимаю, почему это работает.

7 ответов


каждый из методов t возвращает a ссылка к-т. Ссылка-это псевдоним. Так что если вы сделали

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

tAgain.setMinute также изменяет время t.

теперь экстраполируйте этот простой пример на каскадирование. Каждый метод t возвращает ссылку на себя

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

так в выражении:

  t.setHour( 18 ).setMinute( 30 )

t.setHour( 18 ) вызывает setHour на t, затем возвращает ссылку на t. В этом случае ссылка является временной. Таким образом, вы можете думать об этом, как будто выше строка изменилась на следующую при оценке setHour:

  tAgain.setMinute(30);

Т.setHour вернул ссылку -- похож на наш tAgain выше. Просто псевдоним для себя.


причина, по которой это работает правильно, заключается в том, что при вызове

t.setHour( 18 )

возвращаемое значение Time& ссылка на


из-за того, что каждая функция возвращает ссылку на объект this object (возврат *this).

в основном это означает, что каждый раз, когда функция вызывается его внести соответствующие изменения и передает весь объект как справочник. Затем можно совершать вызовы этого возвращаемого объекта.

это также может быть написано следующим образом:

 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.

Это может облегчить понимание того, что происходит.


Это похоже на перегрузку операторов трансляций.

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

вы делаете это, потому что вы изменяете поток и возвращаете его, чтобы его можно было использовать в следующем каскадном вызове при желании. Он продолжает передаваться по ссылке, поэтому он может продолжать идти в следующий сегмент выражения.

вот так:

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

работает! :)


это может помочь, если вы думаете о заявлениях, решаемых по одному шагу за раз.

возьмите, например, следующее:

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

C++ делает то же самое с вызовами функций и всем остальным, что вы делаете в операторе, решая каждый элемент внутри в порядке приоритета оператора. Таким образом, вы можете думать о своем примере, как решается таким же образом:

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

если вы вернулись this вместо *this, и, таким образом, возвращая указатели вместо ссылки, вы получите тот же эффект, за исключением того, что вы замените . С -> (как пример, вы делаете это правильно, используя ссылки). Точно так же, если вы вернули указатель или ссылку на разные объект, вы можете сделать то же самое с этим. Например, предположим, что у вас есть функция, которая возвращает


техника называется способ сцепления. В приведенном примере все методы возвращают один и тот же объект (this), поэтому все они влияют на один и тот же объект. Это не редкость, но полезно знать, что это не обязательно так; некоторые или все методы в цепочке могут возвращать разные объекты. Например, у вас также могут быть такие методы, как:

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

в этом случае вы могли бы сказать:

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

чтобы получить название дня недели. В таком случае ...--2--> возвращает объект Date, который, в свою очередь, используется для вызова dayOfWeek().


потому что когда функция выполняется и возвращается, она возвращает ссылку на себя, чтобы снова вызвать functions.