Подтвердить что ты не робот

Что входит в основную функцию?

Я ищу лучший пример того, что входит в основную функцию программы с помощью С++. В настоящее время я думаю, что возможны два подхода. (Хотя "поля" этих подходов могут быть сколь угодно близки друг к другу)

1: Напишите класс "Мастер", который получает параметры, переданные основной функции, и обрабатывает полную программу в этом классе "Мастер" (конечно, вы также используете другие классы). Поэтому основная функция будет сводиться к минимуму строк.

#include "MasterClass.h"
int main(int args, char* argv[])
{
MasterClass MC(args, argv);
}

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

Я ищу некоторые общие рекомендации о том, как написать основную функцию программы в С++. Я столкнулся с этой проблемой, пытаясь написать несколько unit test для первого подхода, что немного сложно, поскольку большинство методов являются частными.

4b9b3361

Ответ 1

Почему у вас есть один мастер-класс? Какова его единственная область ответственности?

Классы "Мастер" или "приложение" обычно становятся крупными блобами, которые делают слишком много разных вещей. В конечном счете, какой смысл? Что вы купили?

Почему бы не использовать главную функцию для обеспечения этой основной функции? Определите жизненный цикл приложения высокого уровня в main. Он принимает некоторые аргументы командной строки и анализирует их (желательно, делегируя это другой функции или классу), а затем он вызывает некоторые функции настройки, а затем он может ввести какой-то основной цикл, прежде чем выполнять некоторую очистку. В общем, это может дать вам основную функцию, возможно, 10-15 строк, но, вероятно, не более того. Он должен как можно больше делегировать другим классам и функциям. поэтому main сам остается коротким и сладким, но все же имеет цель.

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

Конечно, вы могли бы взять все это и поместить в "основной класс", и вы бы не получили абсолютно ничего, кроме удовлетворения всех Java-луддитов, которые чувствуют, что "все должно быть в классе",.

Ответ 2

Вы описываете два "экстремальных" подхода, ни один из которых не подходит мне. Ни один God Class, ни наличие единственной функции Бога - это правильный способ реализовать любую нетривиальную программу, предназначенную для реального использования.

В вашем main() может быть один вызов MasterClass (хотя я бы предпочел лучше использовать функции разбиения на разделы, например, выполнить любую обработку в командной строке в main(), чтобы отделить MasterClass от детали параметров командной строки). Однако, если этому классу сложно выполнить unit test, это признак проблемы проектирования, и обычно решение состоит в том, чтобы делегировать часть или все свои проверяемые функции другим классам, где их можно легко протестировать в отдельности через публичные интерфейсы.

Ваш второй подход снова может быть проблематичным для unit test, поэтому вы должны стремиться к извлечения методов из него (а затем желательно переместить их в отдельный класс), чтобы сделать мелкозернистые модульные тесты возможными.

Сладкое место, где вы хотите быть, находится где-то между двумя крайностями, сдерживается требованием сделать ваш код пригодным для тестирования.

Стоит подумать о том, как структурировать ваши программы в целом, а не только в контексте main(). Основная идея состоит в том, чтобы разбить его на "куски" (классы и методы), которые

  • достаточно маленький, чтобы его можно было легко понимать, проверять и поддерживать,
  • логически связный.

Ответ 3

Я бы сделал анализ аргументов процесса в основной подпрограмме, а затем создал экземпляр класса, передав более читаемые параметры, чем argc и argv.

Ответ 4

Ваш первый подход очень распространен, хотя класс имеет тенденцию быть названным "Приложение" (или, по крайней мере, содержит слово "Приложение" ), так что сделайте это.

Ответ 5

Сначала я редко использую С++, но я предполагаю, что это не проблема языка.
Ну, я думаю, это сводится к тому, чтобы попробовать в стороне от некоторых вопросов практичности. Я лично предпочитаю использовать макет # 1, но не ставьте подпрограммы командной строки в MasterClass. Для меня это явно принадлежит к основному. МастерClass должен получить анализируемые аргументы (целые числа, FileStreams, что угодно).

Ответ 6

Обычно я вызываю основную функцию (с той же сигнатурой) в пространстве имен приложений:

namespace current_application {
    int main( int argc, char **argv ) {
        // ...
    }
}
int main( int argc, char **argv ) {
    return current_application::main( argc, argv );
}

И затем я обычно использую свой основной (тот, что в пространстве имен) для инициализации приложений:

  • установить локали на стандартный ввод/вывод/ошибку)

  • параметры параметров анализа

  • экземпляр объекта моего основного класса, если он присутствует (эквивалент чего-то типа QApplication)

  • вызовите основную функцию, если она присутствует (эквивалент чего-то вроде QApplication::run)

и обычно предпочитают добавлять блок try catch, чтобы печатать больше информации об отладке в случае сбоя.


Тем не менее, все это очень субъективно; это часть вашего стиля кодирования.

Ответ 7

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

Ответ 8

Пример, который вы указали, просто перемещает главную функцию внутри пространства имен. Я не вижу здесь преимущества. Для меня работает средний подход к дороге с небольшой тенденцией к модели мастер-класса. Объект "Мастер-класс" обычно будет огромным и лучше всего создан в куче. У меня есть основная функция, создающая объект и обрабатывающая любые ошибки, которые могут возникнуть здесь.

class MasterClass {
public:
static MasterClass* CreateInstance( int argc, char **argv );
    // ...
}

int main(int argc, char** argv)
{
    try
    {
         MasterClass mc = MC::CreateInstance(argc, argv);
    }
    catch(...)
    {
        // ...
    }
}

Это также имеет то преимущество, что любая обработка, которая не имеет ничего общего с реальной программной логикой, такой как чтение среды и т.д., не обязательно должна быть помещена в MasterClass. Они могут идти в main(). Хорошим примером является задача надстройки сервера для системы Lotus Domino. Здесь задача должна выполняться только тогда, когда управление передается ему заданием планировщика Domino. Здесь главное будет выглядеть, как показано ниже:

STATUS LNPUBLIC AddInMain(HMODULE hModule, int argc, char far *argv[])
{
     MasterClass mc = MC::CreateInstance(argc, argv);
     while(/* wait for scheduler to give control */)
     {
          STATUS s = mc->RunForTimeSlice();
          if (s != SUCCESS)
               break;
     }
     // clean up
}

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

Ответ 9

Если исключение не имеет обработчика, то оно не указано, вызываются ли деструкторы локальных объектов до std::terminate.

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

Обычно это все, что я помещаю в main, которое иначе просто вызывает cppMain...; -)

Приветствия и hth.,

Ответ 10

Я предпочитаю подход IOC (Inversion of Control) к моим программам.

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

Объект, который он использует для загрузки файлов конфигурации, затем имеет команду "запустить", но то, что запускается (если есть), зависит также от аргументов командной строки.