В чем преимущество возврата объекта в статической функции вместо его построения? - PullRequest
0 голосов
/ 21 февраля 2019

Рассмотрим в качестве примера следующую документацию по Qt Framework, даже если мой вопрос не является специфичным для Qt:

https://doc.qt.io/qt-5/qversionnumber.html

Вы можете найти статическую открытую функцию-член:

QVersionNumber fromString(const QString &string, int *suffixIndex = nullptr)

вместо:

QVersionNumber(const QString &string, int *suffixIndex = nullptr)

в списке конструкторов.

Я видел этот выбор, сделанный во многих библиотеках API, и я не могу понять, в чем преимущество ипочему этот конструктор отсутствует.

Ответы [ 2 ]

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

На самом деле это отличный вопрос.

Причины могут отличаться от сценария к сценарию, но связаны с такими проблемами, как:

  • Насколько читаем конструктор?
  • Я создаю искусственные объекты или излишне дублирую условные выражения для записи конструктора в терминах списка инициализаторов?
  • Может ли мой конструктор иметь неоднозначность с конструктором, предназначенным для выполнения конструирования другого типа?
  • Очевидно ли, что мой конструктор делает без необходимости прописывать имя в коде?

Все вышеперечисленное будет включать некоторую степень субъективности.

гипотетический пример, догадываясь о внутренностях QVersionNumber,

Как бы вы записали это в терминах в списке инициализации?

QVersionNumber 
QVersionNumber::fromString(const QString &string, int *suffixIndex)
{
    std::optional<QVersionNumber> result;
    auto first = string.begin();
    auto last = string.end();
    auto opt_major = maybe_extract_decimal(first, last); // modifies first
    if (not opt_major.has_value())
        result.emplace();
    else
    {
        auto opt_minor = maybe_extract_decimal(first, last); // modifies first
        if (not opt_major.has_value())
            result.emplace(*opt_major);
        else
            result.emplace(*opt_minor);
    }
    if (suffixIndex)
      *suffixIndex = int(std::difference(string.begin(), first);
    return *std::move(result);
}

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

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

Статические методы создания удобны, поскольку они не требуют создания избыточных объектов и могут быть добавлены в код создаваемого ими объекта. Существует много причин для использования конструктора с гарантированным созданием метода.Вот лишь некоторые из них:

  1. Конструктор всегда должен быть завершен с созданием действительного объекта.Использование исключения в конструкторе - очень плохая практика.Что мы можем сделать, если создание объекта невозможно, например, из-за неверных аргументов или неправильного порядка инициализации?В случае метода создания вы можете просто вернуть nullptr или какой-то «неправильный» тип объекта.

  2. Если мы хотим настроить создание объекта без изменения его кода.Например, мы хотим построить объект и настроить его, или у нас нет конструктора для доступных аргументов.Функция-обертка позволяет решить проблему, не касаясь кода класса.Это относится к данному примеру , как вы можете видеть , fromString аргумент разбора строки перед вызовом конструктора.

  3. Мы не знаем, какой тип объекта построить,Это решается во время выполнения.В общем, мы можем вернуть базовый объект и выбрать необходимый класс внутри оболочки.Это позволяет не изменять основной код для выбора конкретного объекта.

  4. Мы хотим контролировать создание всех объектов, чтобы исключить возможные утечки памяти.Например, при деинициализации библиотеки освободите все ресурсы, даже если пользователь забыл это сделать.

Я рекомендую вам ознакомиться с шаблонами проектирования, особенно с шаблоном для творчества.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...