Оператор вывода в одну строку для двоичного дерева - PullRequest
0 голосов
/ 18 февраля 2019

Я написал простой класс двоичного дерева на C ++ и хочу добавить к нему оператор вывода.Моя первая попытка была:

ostream& operator<<(ostream& out, const Tree& tree) {
    out << tree.myData;
    if (tree.myLeft)
        out << "(" << (*tree.myLeft)  << ")";
    if (tree.myRight)
        out << "[" << (*tree.myRight)  << "]";
    return out;
}

(где myLeft и myRight - указатели на левого и правого потомка текущего дерева, соответственно).Это работает правильно, однако, это не достаточно круто, так как он занимает несколько строк и требует несколько раз вывести «out».

В качестве попытки создать однострочный оператор я написал следующее:

ostream& operator<<(ostream& out, const Tree& tree) {
    return (out << tree.myData
        << "(" << (tree.myLeft? *tree.myLeft: "")  << ")"
        << "[" << (tree.myRight? *tree.myRight: "") << "]");
}

Но возникает ошибка:

несовместимые типы операндов ('Tree' и 'const char [1]')

Поэтому я попробовал это:

ostream& operator<<(ostream& out, const Tree& tree) {
    return (&tree?
        out << tree.myData
            << "(" << *(tree.myLeft)  << ")"
            << "[" << *(tree.myRight) << "]":
        out);
}

Это работает на моем компьютере, но генерирует предупреждение, подразумевающее, что это неопределенное поведение:

Ссылка не может быть привязана к нулевому указателю с разыменованным указателем в лунке-определенный код C ++;Можно предположить, что указатель всегда преобразуется в true [-Wundefined-bool-преобразование]

ВОПРОС: Есть ли способ записать этот оператор вывода в простом одиночном утверждении?

1 Ответ

0 голосов
/ 18 февраля 2019

Простое и элегантное решение - перестроить ваше дерево, чтобы оно работало без нулевых указателей.Вместо этого замените текущее использование нулевых указателей указателями на узел дозорного дерева, поведение которого соответствует пустому дереву.

Затем вы можете переписать свой оператор выходного потока следующим образом:

ostream& operator<<(ostream& out, const Tree& tree) {
    if (&tree == &Tree::NULL_TREE_SENTINEL) return out;
    return out << tree.myData
        << "(" << *tree.myLeft  << ")"
        << "[" << *tree.myRight << "]";
}

(Это предполагает наличие соответствующего статического члена внутри Tree, к которому часовые являются указателями, например синглетами.)

В качестве альтернативы, сторожевое дерево может быть экземпляром подкласса Tree с таким поведением.Иногда это называется шаблон нулевого объекта .Однако для его работы требуется динамическая диспетчеризация (т.е. полиморфизм во время выполнения через виртуальные функции-члены).


Кроме этого, вы не совсем правильно диагностируете проблему со своим вторым кодом:

Это работает на моем компьютере

Это , кажется, работает, но на самом деле не работает.Я не знаю, при каких именно обстоятельствах этот код будет делать что-то неприятное.Но, для ясности, ваш код недопустим из-за подвыражений *(tree.myLeft) и *(tree.myRight): эти выражения разыменовывают нулевые указатели, и это никогда не допустимо.Предупреждающее сообщение о тесте &tree является просто признаком этой предыдущей ошибки.

...