#c #recursion #operator-overloading
#c #рекурсия #оператор-перегрузка
Вопрос:
Я нахожусь в процессе изучения рекурсии. Ниже приведена рекурсивная перегрузка оператора вставки для класса, который предоставляет связанный список целых чисел. Он компилируется и запускается, но я не понимаю, почему.
Я понимаю, что при перегрузке оператора вставки вы обычно возвращаете ostream
ссылку, чтобы вызовы могли быть объединены в цепочку. Однако не будет ли эта функция оценивать что-то вроде out << node
, затем to out << out << node
, а затем to out << out << out << node
и т. Д.? При достижении базового варианта и начале возврата кажется, что вы пытаетесь вставить an ostream
в an ostream
, что должно вызвать ошибку, не так ли?
ostream amp; operator<<(ostream amp;out, const IntList amp;intList) {
if (intList.head != nullptr) out << intList.head;
return out;
}
ostream amp; operator<<(ostream amp;out, IntNode *node) {
if (node->next == nullptr) {
out << node->value;
return out;
}
else {
out << node->value << ' ';
node = node->next;
return out << node;
}
}
Ответ №1:
похоже, вы пытаетесь вставить ostream в ostream
Нет. Ваш <<
оператор возвращает an ostream
, но это не означает, что вы вставляете его в другой ostream .
каждый шаг, который вы выполняете в рекурсивной функции, вы вставляете что-то в ostream и возвращаете тот же ostream. См.:
out << node->value;
...
out << node->value << ' ';
вы всегда вставляете некоторое значение в ostream.
это return out << node;
означает, что вы вставите node->значение в ostream и перейдете к следующему узлу (если есть следующий узел).
Для лучшего понимания, здесь итеративный метод, он должен работать точно так же, как ваш рекурсивный:
ostream amp; operator<<(ostream amp;out, const IntList amp;intList) {
IntNode *node = intList.head;
while(node->next != nullptr){
out << node->value << ' ';
node = node->next;
}
out << node->value;
return out;
}
Комментарии:
1. Спасибо, думаю, теперь я все понял. Я думал о
return out << node;
операторе с двумя функциями — одной рекурсивной (<< узел) и одной not (out) — поэтому после того, как последний узел вернет out , следующая функция в стеке разрешится наout << out
etc . На самом деле, это эквивалентноreturn operator<<(out, node);
, поэтому, когда конечный узел возвращает out , это приведет к тому, что все предыдущие вызовы функций будут возвращать out , а возврат amp;out из рекурсивной перегрузки функции оператора вставки позволит связать операторы вставки в «внешний» оператор вставки2. В вашем итеративном примере оператор в цикле while разрешит from
out << node->value << ' ';
toout << ' ';
и, наконец, ссылку наout;
, которая будет отброшена перед следующей итерацией?3. Я исправил итерационный метод, поскольку заметил ошибку. он должен пройти через весь список, вставляя значение каждого узла и пробел. наконец, вставьте значение последнего узла и верните ostream
4. очевидно, вы должны сначала проверить это: IntList.head != nullptr