main()を短くする必要があるのはなぜですか?


87

私は9年以上プログラミングを行ってきました。最初のプログラミング教師のアドバイスによれば、私は常に自分のmain()機能を非常に短くしています。

最初は理由がわからなかった。私は、理解することなく、ただ教授の喜びに耳を傾けました。

経験を積んだ後、コードを正しく設計すれば、ちょっとしたmain()機能が発生することに気付きました。モジュール化されたコードを記述し、単一の責任原則に従うことで、コードを「束」に設計することmain()ができ、プログラムを実行するための触媒としてしか機能しませんでした。

数週間前に早送りして、Pythonのソースコードを見て、main()関数を見つけました。

/* Minimal main program -- everything is loaded from the library */

...

int
main(int argc, char **argv)
{
    ...
    return Py_Main(argc, argv);
}

やったパイソン。短いmain()関数==良いコード。

プログラミングの先生は正しかった。

もっと深く見たいので、Py_Mainを見てみました。全体として、次のように定義されます。

/* Main program */

int
Py_Main(int argc, char **argv)
{
    int c;
    int sts;
    char *command = NULL;
    char *filename = NULL;
    char *module = NULL;
    FILE *fp = stdin;
    char *p;
    int unbuffered = 0;
    int skipfirstline = 0;
    int stdin_is_interactive = 0;
    int help = 0;
    int version = 0;
    int saw_unbuffered_flag = 0;
    PyCompilerFlags cf;

    cf.cf_flags = 0;

    orig_argc = argc;           /* For Py_GetArgcArgv() */
    orig_argv = argv;

#ifdef RISCOS
    Py_RISCOSWimpFlag = 0;
#endif

    PySys_ResetWarnOptions();

    while ((c = _PyOS_GetOpt(argc, argv, PROGRAM_OPTS)) != EOF) {
        if (c == 'c') {
            /* -c is the last option; following arguments
               that look like options are left for the
               command to interpret. */
            command = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (command == NULL)
                Py_FatalError(
                   "not enough memory to copy -c argument");
            strcpy(command, _PyOS_optarg);
            strcat(command, "\n");
            break;
        }

        if (c == 'm') {
            /* -m is the last option; following arguments
               that look like options are left for the
               module to interpret. */
            module = (char *)malloc(strlen(_PyOS_optarg) + 2);
            if (module == NULL)
                Py_FatalError(
                   "not enough memory to copy -m argument");
            strcpy(module, _PyOS_optarg);
            break;
        }

        switch (c) {
        case 'b':
            Py_BytesWarningFlag++;
            break;

        case 'd':
            Py_DebugFlag++;
            break;

        case '3':
            Py_Py3kWarningFlag++;
            if (!Py_DivisionWarningFlag)
                Py_DivisionWarningFlag = 1;
            break;

        case 'Q':
            if (strcmp(_PyOS_optarg, "old") == 0) {
                Py_DivisionWarningFlag = 0;
                break;
            }
            if (strcmp(_PyOS_optarg, "warn") == 0) {
                Py_DivisionWarningFlag = 1;
                break;
            }
            if (strcmp(_PyOS_optarg, "warnall") == 0) {
                Py_DivisionWarningFlag = 2;
                break;
            }
            if (strcmp(_PyOS_optarg, "new") == 0) {
                /* This only affects __main__ */
                cf.cf_flags |= CO_FUTURE_DIVISION;
                /* And this tells the eval loop to treat
                   BINARY_DIVIDE as BINARY_TRUE_DIVIDE */
                _Py_QnewFlag = 1;
                break;
            }
            fprintf(stderr,
                "-Q option should be `-Qold', "
                "`-Qwarn', `-Qwarnall', or `-Qnew' only\n");
            return usage(2, argv[0]);
            /* NOTREACHED */

        case 'i':
            Py_InspectFlag++;
            Py_InteractiveFlag++;
            break;

        /* case 'J': reserved for Jython */

        case 'O':
            Py_OptimizeFlag++;
            break;

        case 'B':
            Py_DontWriteBytecodeFlag++;
            break;

        case 's':
            Py_NoUserSiteDirectory++;
            break;

        case 'S':
            Py_NoSiteFlag++;
            break;

        case 'E':
            Py_IgnoreEnvironmentFlag++;
            break;

        case 't':
            Py_TabcheckFlag++;
            break;

        case 'u':
            unbuffered++;
            saw_unbuffered_flag = 1;
            break;

        case 'v':
            Py_VerboseFlag++;
            break;

#ifdef RISCOS
        case 'w':
            Py_RISCOSWimpFlag = 1;
            break;
#endif

        case 'x':
            skipfirstline = 1;
            break;

        /* case 'X': reserved for implementation-specific arguments */

        case 'U':
            Py_UnicodeFlag++;
            break;
        case 'h':
        case '?':
            help++;
            break;
        case 'V':
            version++;
            break;

        case 'W':
            PySys_AddWarnOption(_PyOS_optarg);
            break;

        /* This space reserved for other options */

        default:
            return usage(2, argv[0]);
            /*NOTREACHED*/

        }
    }

    if (help)
        return usage(0, argv[0]);

    if (version) {
        fprintf(stderr, "Python %s\n", PY_VERSION);
        return 0;
    }

    if (Py_Py3kWarningFlag && !Py_TabcheckFlag)
        /* -3 implies -t (but not -tt) */
        Py_TabcheckFlag = 1;

    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
        Py_InspectFlag = 1;
    if (!saw_unbuffered_flag &&
        (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0')
        unbuffered = 1;

    if (!Py_NoUserSiteDirectory &&
        (p = Py_GETENV("PYTHONNOUSERSITE")) && *p != '\0')
        Py_NoUserSiteDirectory = 1;

    if ((p = Py_GETENV("PYTHONWARNINGS")) && *p != '\0') {
        char *buf, *warning;

        buf = (char *)malloc(strlen(p) + 1);
        if (buf == NULL)
            Py_FatalError(
               "not enough memory to copy PYTHONWARNINGS");
        strcpy(buf, p);
        for (warning = strtok(buf, ",");
             warning != NULL;
             warning = strtok(NULL, ","))
            PySys_AddWarnOption(warning);
        free(buf);
    }

    if (command == NULL && module == NULL && _PyOS_optind < argc &&
        strcmp(argv[_PyOS_optind], "-") != 0)
    {
#ifdef __VMS
        filename = decc$translate_vms(argv[_PyOS_optind]);
        if (filename == (char *)0 || filename == (char *)-1)
            filename = argv[_PyOS_optind];

#else
        filename = argv[_PyOS_optind];
#endif
    }

    stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0);

    if (unbuffered) {
#if defined(MS_WINDOWS) || defined(__CYGWIN__)
        _setmode(fileno(stdin), O_BINARY);
        _setmode(fileno(stdout), O_BINARY);
#endif
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
        setvbuf(stderr, (char *)NULL, _IONBF, BUFSIZ);
#else /* !HAVE_SETVBUF */
        setbuf(stdin,  (char *)NULL);
        setbuf(stdout, (char *)NULL);
        setbuf(stderr, (char *)NULL);
#endif /* !HAVE_SETVBUF */
    }
    else if (Py_InteractiveFlag) {
#ifdef MS_WINDOWS
        /* Doesn't have to have line-buffered -- use unbuffered */
        /* Any set[v]buf(stdin, ...) screws up Tkinter :-( */
        setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ);
#else /* !MS_WINDOWS */
#ifdef HAVE_SETVBUF
        setvbuf(stdin,  (char *)NULL, _IOLBF, BUFSIZ);
        setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
#endif /* HAVE_SETVBUF */
#endif /* !MS_WINDOWS */
        /* Leave stderr alone - it should be unbuffered anyway. */
    }
#ifdef __VMS
    else {
        setvbuf (stdout, (char *)NULL, _IOLBF, BUFSIZ);
    }
#endif /* __VMS */

#ifdef __APPLE__
    /* On MacOS X, when the Python interpreter is embedded in an
       application bundle, it gets executed by a bootstrapping script
       that does os.execve() with an argv[0] that's different from the
       actual Python executable. This is needed to keep the Finder happy,
       or rather, to work around Apple's overly strict requirements of
       the process name. However, we still need a usable sys.executable,
       so the actual executable path is passed in an environment variable.
       See Lib/plat-mac/bundlebuiler.py for details about the bootstrap
       script. */
    if ((p = Py_GETENV("PYTHONEXECUTABLE")) && *p != '\0')
        Py_SetProgramName(p);
    else
        Py_SetProgramName(argv[0]);
#else
    Py_SetProgramName(argv[0]);
#endif
    Py_Initialize();

    if (Py_VerboseFlag ||
        (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) {
        fprintf(stderr, "Python %s on %s\n",
            Py_GetVersion(), Py_GetPlatform());
        if (!Py_NoSiteFlag)
            fprintf(stderr, "%s\n", COPYRIGHT);
    }

    if (command != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c' */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    if (module != NULL) {
        /* Backup _PyOS_optind and force sys.argv[0] = '-c'
           so that PySys_SetArgv correctly sets sys.path[0] to ''
           rather than looking for a file called "-m". See
           tracker issue #8202 for details. */
        _PyOS_optind--;
        argv[_PyOS_optind] = "-c";
    }

    PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);

    if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) &&
        isatty(fileno(stdin))) {
        PyObject *v;
        v = PyImport_ImportModule("readline");
        if (v == NULL)
            PyErr_Clear();
        else
            Py_DECREF(v);
    }

    if (command) {
        sts = PyRun_SimpleStringFlags(command, &cf) != 0;
        free(command);
    } else if (module) {
        sts = RunModule(module, 1);
        free(module);
    }
    else {

        if (filename == NULL && stdin_is_interactive) {
            Py_InspectFlag = 0; /* do exit on SystemExit */
            RunStartupFile(&cf);
        }
        /* XXX */

        sts = -1;               /* keep track of whether we've already run __main__ */

        if (filename != NULL) {
            sts = RunMainFromImporter(filename);
        }

        if (sts==-1 && filename!=NULL) {
            if ((fp = fopen(filename, "r")) == NULL) {
                fprintf(stderr, "%s: can't open file '%s': [Errno %d] %s\n",
                    argv[0], filename, errno, strerror(errno));

                return 2;
            }
            else if (skipfirstline) {
                int ch;
                /* Push back first newline so line numbers
                   remain the same */
                while ((ch = getc(fp)) != EOF) {
                    if (ch == '\n') {
                        (void)ungetc(ch, fp);
                        break;
                    }
                }
            }
            {
                /* XXX: does this work on Win/Win64? (see posix_fstat) */
                struct stat sb;
                if (fstat(fileno(fp), &sb) == 0 &&
                    S_ISDIR(sb.st_mode)) {
                    fprintf(stderr, "%s: '%s' is a directory, cannot continue\n", argv[0], filename);
                    fclose(fp);
                    return 1;
                }
            }
        }

        if (sts==-1) {
            /* call pending calls like signal handlers (SIGINT) */
            if (Py_MakePendingCalls() == -1) {
                PyErr_Print();
                sts = 1;
            } else {
                sts = PyRun_AnyFileExFlags(
                    fp,
                    filename == NULL ? "<stdin>" : filename,
                    filename != NULL, &cf) != 0;
            }
        }

    }

    /* Check this environment variable at the end, to give programs the
     * opportunity to set it from Python.
     */
    if (!Py_InspectFlag &&
        (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0')
    {
        Py_InspectFlag = 1;
    }

    if (Py_InspectFlag && stdin_is_interactive &&
        (filename != NULL || command != NULL || module != NULL)) {
        Py_InspectFlag = 0;
        /* XXX */
        sts = PyRun_AnyFileFlags(stdin, "<stdin>", &cf) != 0;
    }

    Py_Finalize();
#ifdef RISCOS
    if (Py_RISCOSWimpFlag)
        fprintf(stderr, "\x0cq\x0c"); /* make frontend quit */
#endif

#ifdef __INSURE__
    /* Insure++ is a memory analysis tool that aids in discovering
     * memory leaks and other memory problems.  On Python exit, the
     * interned string dictionary is flagged as being in use at exit
     * (which it is).  Under normal circumstances, this is fine because
     * the memory will be automatically reclaimed by the system.  Under
     * memory debugging, it's a huge source of useless noise, so we
     * trade off slower shutdown for less distraction in the memory
     * reports.  -baw
     */
    _Py_ReleaseInternedStrings();
#endif /* __INSURE__ */

    return sts;
}

全能の神...それはタイタニックを沈めるのに十分な大きさです。

Pythonは「プログラミング入門101」のトリックを行い、すべてmain()のコードを「main」に非常に類似した別の関数に移動しただけのようです。

私の質問は次のとおりです。このコードはひどく書かれているのですか、それとも短いメイン関数を持つ他の理由がありますか?

今のところ、これを行うこととコードをにPy_Main()戻すこととの間に違いはまったくありませんmain()。これを考えるのは間違っていますか?


4
codereviews.stackexchange.comの方が良いのではないでしょうか?
フーバー

38
@Luzhin、いいえ。Pythonのソースコードをレビューするようにだれにも求めていません。これはプログラミングの質問です。
リウォーク

3
TBHは、半分のコードは、オプションの処理で、いつでもあなたのプログラムがたくさんのオプションのサポート、およびカスタムプロセッサを書き、これはあなたが...やって終わるものです
ニム

7
@Starいいえ、Programmers.SEはベストプラクティス、コーディングスタイルなどのためでもあります。実際、私はこのサイトを訪れています。
Mateen Ulhaq

4
@Nim、私はそれが何をしているかであることを理解、しかしとしてそれを書くためではない理由はないoptions = ParseOptionFlags(argc,argv)ところoptionsであるstruct変数を含むがPy_BytesWarningFlagPy_DebugFlagなど...
riwalk

回答:


137

mainライブラリからエクスポートすることはできませんが、エクスポートすることはできます。Py_Mainそのライブラリを使用している人は、同じプログラムで異なる引数を使用してPythonを何度も「呼び出す」ことができます。その時点pythonで、ライブラリの単なる別のコンシューマーになり、ライブラリー関数のラッパーに過ぎません。Py_Main他のみんなと同じように呼び出します。


1
良い答えがあります。
リウォーク

26
@Shoosh、インポートできないと言う方が正確かもしれません。C ++標準では、独自のコードから呼び出すことは禁止されています。また、そのリンケージは実装定義です。また、通常はライブラリに実行させたくないmain呼び出しから効果的に戻りexitます。
ロブ・ケネディ

3
@ Coder、C ++ 03§3.6.1/ 5を参照:「returnステートメントはmain、メイン関数を終了exitし、戻り値を引数として呼び出す効果があります。」§18.3/ 8も参照してください。これは、を呼び出すときに「静的ストレージ期間を持つオブジェクトが破棄される」と「開いているすべてのCストリームがフラッシュされる」ことを説明していますexit。C99にも同様の言語があります。
ロブ・ケネディ

1
@Coder、exitmainが無関係かどうか。の動作については説明していませんexit。の動作について説明していますmain。そして、の挙動がmain 含まれての行動exitそれが何であれを。それが、インポートと呼び出しを望ましくないものにするmain理由です(そのようなことを行うことが可能または許可されている場合)。
ロブ・ケネディ

3
@Coder、から戻ってもコンパイラmainを呼び出す効果がない場合exit、コンパイラは標準に準拠していません。標準がそのような振る舞いを規定してmainいるということ、それについて何か特別なものがあることを証明しています。特別なことmainは、そこから戻ることはを呼び出す効果があるということexitです。(どのようにそれはそれは、コンパイラは単に静的オブジェクトを破壊する機能のエピローグにコードを挿入することができライターをコンパイラに任されて呼び出しを行います。atexitファイルをフラッシュし、ルーチンを、プログラム終了-もう一度、あなたはライブラリにしたいものではありません、 。)
ロブケネディ

42

それはそれはありませんmainあなたは避けなければならない限りはあまりすべきではない任意の長すぎる機能を。main関数の特殊なケースです。長い関数は非常に扱いにくくなり、保守性が低下し、一般に作業が難しくなります。関数(およびmain)を短くすることにより、通常、コードの品質が向上します。

あなたの例では、コードをmain


9
黄金の言葉は「再利用」かもしれません。long mainはあまり再利用できません。
S.Lott

1
@S-それは黄金の言葉です。もう1つはOMGです!!! ADHDジャストインキック!!!! または素人用語で:読みやすさ。
エドワードストレンジ

3
main()には、他の関数にはないいくつかの制限もあります。
マーティンヨーク

1
また、main()には実際の意味はありません。あなたのコードはすべて、他のプログラマにとって何かを意味するはずです。mainを使用して引数を解析しますが、それで終わりです。数行を超える場合は、それを委任することもできます。
ビルK

@Bill K:引数を解析するためだけにmain()を使用する(そしてプログラムの残りの部分を開始する)ことも、単一責任の原則に準拠しています。
ジョルジオ

28

main()短くする理由の1つは、単体テストにあります。 main()は単体テストができない1つの関数なので、動作の大部分を単体テストが可能な別のクラスに抽出するのが理にかなっています。これはあなたが言ったことと一緒に行く

モジュール化されたコードを記述し、単一の責任原則に従うことで、コードを「束」で設計することができ、main()はプログラムを実行する触媒としてのみ機能しました。

注:ここ からアイデアを得ました


別の良いもの。その側面を考えたことはありません。
リウォーク

16

main長くすることはめったにありません。以下のように任意のそれが長いかどう関数(またはメソッド)あなたはおそらくリファクタリングの機会を逃しています。

上記の特定のケースでmainは、すべての複雑さが考慮されるため、短いPy_Mainです。コードをPythonシェルのように動作させたい場合は、多くの手間をかけずにそのコードを使用できます。(mainライブラリに入れるとうまく動作しないため、そのようにファクタリングする必要があります。そうすると、奇妙なことが起こります。)

編集:
明確にするためmainに、静的ライブラリには明示的なリンクがないため、静的リンクに入れることはできません(したがって、参照されているものとオブジェクトファイルにコロケートしない限り、恐ろしいです) !)共有ライブラリは通常(同様に、混乱を防ぐために)同様に扱われますが、多くのプラットフォームでは、共有ライブラリはブートストラップセクションのない単なる実行可能ファイル(mainその最後で最も見える部分) )。


1
要するに、mainライブラリに入れないでください。動作しないか、ひどく混乱させます。しかし、ほとんどすべての作業をlib内の関数に委任すること、多くの場合賢明です。
ドナルドフェローズ

6

メインは、機能を短くするのと同じ理由で短くする必要があります。人間の脳は、パーティション化されていない大量のデータを一度にメモリに保持するのに苦労しています。それを論理的なチャンクに分割して、他の開発者(およびあなた自身)が消化し、推論するのを容易にします。

そして、はい、あなたの例はひどく読みにくいです。


はい、私は常にコード自体がひどいものであると疑っていました(ただし、質問はコード自体ではなくコードの配置に関するものです)。その結果、私のPythonのビジョンが本質的に損なわれているのではないかと心配しています。
riwalk11年

1
@stargazer:コード自体がひどいことはわかりませんが、人間が消費するためにうまく構成されていないだけです。そうは言っても、うまく機能し、優れたパフォーマンスを発揮する「ugい」コードがたくさんあります。コードの美しさだけがすべてではありませんが、可能な限りクリーンなコードを書くために常に最善を尽くす必要があります。
エドS.

あー 私にとって、彼らはまったく同じです。クリーンなコードはより安定する傾向があります。
リウォーク

コードはひどいものではありません。主にスイッチケースと複数のプラットフォームの処理があります。何が恐ろしいと思いますか?
フランチェスコ

@Francesco:申し訳ありませんが、機能的ではなく、メンテナンスと読みやすさの観点から「ひどい」です。
エドS.

1

一部の人々は、他に何もしないが、別の関数への呼び出しをラップする50以上の関数を楽しんでいます。メインプログラムロジックを実行する通常のメイン機能を優先します。もちろんよく構成されています。

int main()
{
CheckInstanceCountAndRegister();
InitGlobals();
ProcessCmdParams();
DoInitialization();
ProgramMainLoopOrSomething();
DeInit();
ClearGlobals();
UnregisterInstance();
return 0; //ToMainCRTStartup which cleans heap, etc.
}

それをラッパーでラップする必要がある理由はわかりません。

それは純粋に個人的な好みです。


1
それはドキュメントだからです。(ほとんど)コメントを書く必要なく、この方法でコードを書くことができます。そして、コードを変更すると、ドキュメントは自動的に変更されます:-)。
オリバーワイラー

1

メインだけでなく、すべての機能を短くすることがベストプラクティスです。ただし、「ショート」は主観的なものであり、プログラムのサイズと使用している言語によって異なります。


0

mainコーディング標準以外の、長さの要件はありません。main関数は他の関数と同じであり、そのため、複雑さは10(またはコーディング標準で指定されているもの)未満でなければなりません。それだけです、他のものはむしろ議論の余地があります。

編集する

main短くしないでください。または長い。設計に基づいて実行するために必要な機能を含み、コーディング標準に準拠する必要があります。

あなたの質問の特定のコードに関して-はい、それはいです。

2番目の質問について-はい、あなたは間違っています。そのコードをすべてmainに戻すと、Py_Main外部からリンクすることでモジュールとしてライブラリとして使用できなくなります。

今、私は明確ですか?


私はそれ長くなることができるかどうかを尋ねませんでした。なぜ長くはいけないのかと尋ねました。
リウォーク

「10未満の複雑さ」?そのための測定単位はありますか?
ドナルドフェローズ

@ Stargazer712関数の長さは通常、コーディング標準によっても規制されています。それは読みやすさの問題であり(そして複雑さ、通常、長い関数は分岐して複雑さが20をmainはるかに超えるようになります)、私が言ったように- この点で他の関数と違いはありません。
littleadv

@Donal-はい、リンクをクリックします。
littleadv

私はこの1つの芽を落とさなければなりません。質問の意図が完全に欠落しています。
リウォーク

0

GCC 4.6.1 Changelogからmainを短くしておくための新しい実用的な理由は次のとおりです。

名前付きセクションをサポートするほとんどのターゲットでは、起動時にのみ使用される関数(静的コンストラクターと メイン)、終了時にのみ使用される関数、コールドであると検出された関数は 、個別のテキストセグメントサブセクションに配置されます。これにより、-freorder-functions機能が拡張され、同じスイッチで制御されます。目標は、大規模なC ++プログラムの起動時間を改善することです。

私が追加した強調表示。


0

ほんの少しのソフトウェアが優れているからといって、そのソフトウェアの背後にあるすべてのコードが優れていると仮定しないでください。優れたソフトウェアと優れたコードは同じものではありません。優れたソフトウェアが優れたコードに裏付けられている場合でも、大規模なプロジェクトでは標準がずれてしまうことが避けられません。

短いmain関数を使用することをお勧めしますが、実際には、短い関数を使用する方が良いという一般的なルールの特別な場合です。短い関数は理解しやすく、デバッグしやすく、プログラムをより表現力豊かにする一種の「単一目的」設計にこだわることが容易です。mainおそらく、プログラムを理解したい人は理解しなければならないmainが、コードベースのより曖昧なコーナーはあまり頻繁に訪れないので、ルールに固執するより重要な場所です。

しかし、Pythonコードベースは、Py_Mainこのルールを実行するためにコードをプッシュするのではなくmain、ライブラリからエクスポートしたり、関数として呼び出したりできないためです。


-1

上記にはいくつかの技術的な答えがありますが、それはさておきましょう。

メインはブートストラップである必要があるため、短くする必要があります。メインは、作業を行う少数のオブジェクト(多くの場合1つ)をインスタンス化します。他の場所と同様に、これらのオブジェクトは適切に設計され、凝集性があり、疎結合で、カプセル化されている必要があります...

1行のメインで別のモンスターメソッドを呼び出すには技術的な理由があるかもしれませんが、原則としては正しいです。ソフトウェアエンジニアリングの観点からは、何も得られていません。モンスターメソッドを呼び出すメインの1行と、メイン自体がモンスターメソッドであるかのどちらかを選択した場合、後者はそれほど悪くありません。


「C ++コードはオブジェクトとオブジェクトのみを使用する必要がある」と仮定しています。それは真実ではありません。C++はマルチパラダイム言語であり、他の言語のようにすべてをオブジェクト指向の型に強制しません。
ベンフォークト
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.