Как работает каскадирование" это"?
у меня есть следующий класс интерфейс:
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
.