【问题标题】:C++ main() in a large OOP project大型 OOP 项目中的 C++ main()
【发布时间】:2010-11-16 01:36:33
【问题描述】:

这可能是一个简短的问题,但我从未找到令人满意的答案:

main() 函数在大型 C++ 项目中通常包含哪些代码?认为它通常只是初始化一个(包装)类对象并调用其中的一个函数来启动它是一个错误的假设吗?

为什么 main() 首先不是一个方法?是为了保持与 C 的向后兼容性吗?

【问题讨论】:

  • 它不是成员函数的原因是你需要一种方法来指定它是哪个类的成员函数。 C++ 没有 Java 的 manifest,也没有反射。
  • 从更概念的层面来看,每个程序都需要一个入口点,在“经典”C++ 的情况下,这是在编译器生成的可执行文件中,当程序启动时,不存在该 main 的类可能是一种方法。在解释型语言中,运行时首先执行并在应用程序启动之前设置一个上下文以供运行,因此如果语言/运行时允许/希望,入口点是某个先前设置类的方法/成员是可能的。
  • @Mark:什么?编译器负责在 main() 执行之前发出代码以初始化各种事物,包括类的静态成员。在某种程度上可以说类在 C++ 中运行时完全存在,在调用入口点之前存在大量类。甚至可能存在大量物体。
  • @onebyone 一个“标准”c++ 编译器发出代码来初始化静态成员和对象,它被告知,stdlib 的某些实现或用户代码可能创建静态成员/类/对象无关紧要这个问题。 C++ 没有按照规范创建 main 可能是其成员的根类。

标签: c++ oop main


【解决方案1】:

在我的代码中,它基本上是一个构造函数调用,可能是一个方法调用,以及一些异常处理。这是我自己的项目的主要内容(省略了标题和 cmets,并且格式被 SO 弄乱了,像往常一样):

int main( int argc, char * argv[] ) {
    int result = 0;
    try {
        CLIHandler ch( argc, argv );
        result = ch.ExecCommand();
    }
    catch( const Exception & ex ) {
        result = ExceptionHandler::HandleMyError( ex );
    }
    catch( const std::exception & ex ) {
        result = ExceptionHandler::HandleOtherError( ex );
    }
    catch( ... ) {
        result = ExceptionHandler::HandleUnknownError();
    }
    return result;
}

【讨论】:

  • 为什么不把你所有的result = 替换成return
  • 把你的嘴洗干净!你有没有听说过这样的要求:在所有结构良好的代码中,一个函数必须只有一个出口点????但说真的,我的方法更容易调试,因为你有一个变量要检查。
  • 啊,我明白了,哈哈。你吓到我了。我当时想,“FUUU-什么?!”。我想我从来不需要检查返回变量,我的错误处理程序将它与异常一起打印出来。否则我们的代码是一样的。
  • +1 表示我喜欢并鼓励大家使用的主要内容。我使用的是一个异常处理程序,它只在 catch(...) 子句中调用 ExceptionHandler::handle() 。 handle 方法在 try-catch 中重新抛出,您可以在其中进行不同的异常处理。更简单?更具可读性?错误处理集中在特定类中...您的口味...
  • @jalf 那是个笑话!我也鼓励使用多个退出点——它几乎总是让代码更清晰。
【解决方案2】:

我的通常是这样

  • 命令行解析
  • 顶级对象的初始化
  • 异常处理
  • 进入主“exec”循环

据我了解,int main(int argc, char *argv[]) 本质上是一个约定,因为C 的传统。从来没有让我觉得奇怪,而是很有用。毕竟 C++ 扩展了 C ......(是的,它们之间存在细微差别,但这不是这里的问题)。

【讨论】:

    【解决方案3】:

    是的,原因是向后兼容。 main 是生成可执行文件的 C 程序中唯一允许的入口点,因此在 C++ 程序中也是如此。

    至于在 C++ 主程序中做什么,这取决于。一般来说,我曾经:

    • 执行全局初始化(例如日志子系统)
    • 解析命令行参数并定义包含它们的适当类
    • 分配一个应用程序对象,设置它等等。
    • 运行应用程序对象(在我的例子中,是一个无限循环方法。GUI 编程)
    • 在对象完成其任务后进行最终确定。

    哦,我忘记了应用程序中最重要的部分

    • 显示启动画面

    【讨论】:

      【解决方案4】:

      简短的回答:视情况而定。它很可能会创建一些在程序运行期间需要的本地对象,配置它们,告诉它们彼此的信息,并在其中一个上调用长时间运行的方法。

      程序需要一个入口点。如果main 必须是对象上的方法,它应该是什么类类型?

      使用main 作为全局入口点,它可以选择要设置的内容。

      【讨论】:

        【解决方案5】:

        我的 main() 函数经常构造各种顶级对象,让它们相互引用。这有助于最大限度地减少耦合,将不同顶级对象之间的确切关系限制在主对象中。

        这些顶级对象通常具有不同的生命周期,包括 init()、stop() 和 start() 方法。 main() 函数管理使对象进入所需的运行状态,等待任何表明该关闭的时间,然后以受控方式关闭所有内容。同样,这有助于保持事物正确解耦,并将顶级生命周期管理保持在一个易于理解的位置。我在反应式系统中经常看到这种模式,尤其是那些有很多线程的系统。

        【讨论】:

          【解决方案6】:

          通过在高级链接器选项下的项目设置中选择入口点,您可以在 MSVC++ 编译器中使用静态类成员函数代替 main。

          这真的取决于你的项目,你想在那里放置什么......如果它很小,你也可以在那里放置消息循环、初始化和关闭代码。在较大的项目中,您将不得不将它们移动到它们自己的类/函数中,或者更少有一个单一的入口点函数。

          【讨论】:

            【解决方案7】:

            并非所有 C++ 应用程序都是 OOP,无论哪种方式,所有代码都需要某个入口点才能开始。

            当我编写 OOP 代码时,我的 main() 倾向于包含一个对象实例化,可能由一些用户输入进行。我这样做是因为我觉得“工作”是在一个对象内完成的,否则代码不是以 OOP 的“精神”编写的。

            【讨论】:

              【解决方案8】:

              我通常使用 main 来读取命令行,初始化全局变量,然后调用相应的函数/方法。

              【讨论】:

                【解决方案9】:

                真正的大型项目往往不仅仅包含一个程序。因此将有几个可执行文件,每个都有自己的主文件。顺便说一句,这些可执行文件通过队列进行异步通信是很常见的。

                是的,每个 main 确实往往非常小,初始化一个框架或其他什么。

                你的意思是为什么 main() 是一个函数而不是类的方法?那么,它将是什么类的方法?我认为这主要是 C++ 从 C 中继承下来的,但是......一切都必须从某个地方开始 :-)

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-02-23
                  • 2023-03-12
                  • 1970-01-01
                  相关资源
                  最近更新 更多