Вторник, 12 января 2021 19:00

Отладка классов в Qt5 с помощью QDebug

Россия

Работая с классами в Qt5 вам неоднократно приходилось сталкиваться с отладкой, при этом строчка вида:

qDebug() << value;

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

Если же вы хотите вывести значение полей экземпляра класса, тут qDebug() пасует – он попросту ничего не знает о вашем классе и всё, что вы получите в результате - строку вида 0x19e8aa45460.

Сегодня мы рассмотрим перегрузку оператора << для класса CountryFlag для последующего использования в конструкциях вида:

CountryFlag flag;
qDebug() << flag;

Создаем класс

Для тестов нам понадобится класс, мы будем использовать созданный в предыдущих статьях CountryFlag:

Заголовок:

#ifndef COUNTRYFLAG_H
#define COUNTRYFLAG_H

#include <QString>



class CountryFlag
{
public:
    CountryFlag();
    CountryFlag(int id, QString name, QString icon);
    QString getIcon() const;
    void setIcon(const QString &value);

    QString getName() const;
    void setName(const QString &value);

    int getId() const;
    void setId(int value);

private:
    int id;
    QString icon;
    QString name;
};

#endif // COUNTRYFLAG_H

Реализация:

#include "countryflag.h"

CountryFlag::CountryFlag()
{

}

CountryFlag::CountryFlag(int id, QString name, QString icon)
{
    this->id = id;
    this->name = name;
    this->icon = icon;
}

QString CountryFlag::getIcon() const
{
    return icon;
}

void CountryFlag::setIcon(const QString &value)
{
    icon = value;
}

QString CountryFlag::getName() const
{
    return name;
}

void CountryFlag::setName(const QString &value)
{
    name = value;
}

int CountryFlag::getId() const
{
    return id;
}

void CountryFlag::setId(int value)
{
    id = value;
}

Заполним класс данными: 

CountryFlag flag1 = CountryFlag(1, "Russia", "russia.png");
CountryFlag flag2 = CountryFlag(2, "Belarus", "belarus.png");

Теперь, для того, чтобы проверить какие данные содержаться в полях экземпляра класса нам нужно написать что-то вроде этого:

qDebug() << flag1.getName();
qDebug() << flag1.getId();

и так далее, что неудобно и громоздко.

Выход – добавить специальный метод toString(), который выведет все необходимые значения в виде компактной строки.

Добавляем метод toString()

QString CountryFlag::toString() const
{
    QString s;
    QTextStream out(&s);

    out << "CountryFlag( " << "id: " << this->getId() << "," << " name: " << this->getName() << "," << " icon: " << this->getIcon() << " )";
    return s;
} 

Добавим строку

qDebug() << flag1.toString();

Запустим – в консоли увидим:

"CountryFlag( id: 1, name: Russia, icon: russia.png )"

Все работает, как нужно. Но использование метода toString() слишком длинно, мы хотим использовать строку вида:

qDebug() << flag1;

Для этого нам придется перегрузить оператор <<

Перегрузка оператора <<

Для использования нашего класса с QDebug мы должны перегрузить оператор <<.

Обратите внимание, мы перегружаем его глобально!

В заголовочном файле класса добавим строку в конец файла, за закрывающей скобкой описания класса }; это важно!

QDebug operator<<(QDebug debug, const CountryFlag &flag);

Реализация

QDebug operator<<(QDebug debug, const CountryFlag &flag)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << "CountryFlag( " << "id: " << QString::number(flag.getId()) << "," << " name: " << flag.getName() << "," << " icon: " << flag.getIcon() << " )";
    return debug;
}

Пропишем

qDebug() << flag1;

Запустим:

CountryFlag( id: "1", name: "Russia", icon: "russia.png" )

Обратите внимание мы дублируем код из метода toString(), это вынужденная мера, в противном случае мы получим такую строку:

"CountryFlag( id: 1, name: Russia, icon: russia.png )"

Обратите внимание мы используем

const CountryFlag &flag

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

Перегружаем << для указателя

Помимо простой переменной у нас может быть указатель на экземпляр класса, давайте добавим код:

CountryFlag *flag3 = new CountryFlag(1, "Russia", "russia.png");
qDebug() << flag3;

Запустим – результат неожиданный:

0x209a3c67bf0

Всё дело в том, что мы передаем указатель вместо константной ссылки, а следовательно qDebug() не использует перегруженный метод созданный нами.

Чтобы решить эту проблему, еще раз перегрузим оператор <<  на этот раз с указателем:

Заголовок:

QDebug operator<<(QDebug debug, const CountryFlag *flag);

Реализация

QDebug operator<<(QDebug debug, const CountryFlag *flag)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << *flag;
    return debug;
}

Запускаем – результат:

CountryFlag( id: "1", name: "Russia", icon: "russia.png" )

Здесь все просто мы разыменовываем ссылку и передаем ее QDebug, а он уже использует перегруженный оператор для вывода строки.

Заключение

Сегодня мы рассмотрели использование QDebug() для отладки классов в Qt5 с помощью перегруженного оператора <<.

Добавили метод toString() для вывода значения полей класса в виде строки.

Перегрузили оператор << для экземпляра класса CountryFlag.

Перегрузили оператор << указателя на экземпляра класса CountryFlag.

 

Прочитано 1427 раз Последнее изменение Вторник, 12 января 2021 16:37