在这种情况下我应该使用引用成员吗?

Should I use references members in this case?

我是一名计算机科学专业的学生,​​我正在自学 C++ 并尝试编写一个干净的 C++ 程序。

这是我的问题: 我正在编写一个 App class,它将成为程序的主要 class,我希望我的很多 classes 可以访问将要创建的 App 对象在主函数中。

基本上main函数就是这样

int main(int argc, char *argv[])
{
   App myApp;

   return myApp.run();
}

应用程序 class 将有许多来自 classes 的对象需要参考(或者在这种情况下还有更好的东西?)应用程序。 这是一个 class 需要它的例子

class AppStateHandler{
private:
    /// < Reference to the App
    App& m_app;
public:
    AppStateHandler(); // How can I initialize m_app with that ??

    /// @param app The app the AppStateHandler will work with
    AppStateHandler(App &app);
};

这是我的问题,在这种情况下使用引用作为 class 成员不好吗?我应该使用某种智能指针吗? 在使用引用的情况下,我无法创建 默认构造函数 因为 m_app 必须在构造函数初始化列表中初始化 所以, 没有默认构造函数不好吗?

如果您对如何改进我的代码有任何建议,我很感兴趣。

非常感谢!

编辑:我实际上想创建一个 AppStateHandler 作为 App 的成员。主函数中声明的唯一对象是 App.

在这种情况下使用引用意味着应用程序不能为 NULL。但是只有在保证对象的生命周期始终在父对象的生命周期内时才使用引用。如果没有,使用智能指针。

不使用默认构造函数一点也不坏。

我认为这不是 "reference VS pointer" 问题。它看起来更像是对象的生命周期和所有权管理。

有很多方法可以确保推荐人在推荐人的生命周期内。

在您的例子中,您在 main() 的堆栈中构建了它们,这是正确的。或者您可以使 AppStateHandler 成为 App 的成员,具体取决于您的设计目的。

需要注意的是,随着 AppStateHandler 的增长,它将有很多成员 classes/objects, 方法,每个方法只做少量工作,实际上并不需要访问全App。将整个 App 传递给它们中的每一个很快会使您的代码变得令人讨厌。

因此,再次强调,根据您的设计目的,无论您选择指针还是引用,都不要传入太多。

P.S。我认为使用 shared_ptr/unique_ptr 跨范围管理 lifetime/ownership 表明设计不佳。 99% 的情况下,您可以通过 RAII 等其他设计技术避免所有权转移的必要性。智能指针在绝对必要时用于另外1%。

您可以使用引用,甚至可以使用智能指针(尽管这样做没有什么意义),但您的问题需要另一种解决方案:singleton.

要使用单例模式,您可以向 App class 添加一个静态方法,它只负责 return 对唯一 App 对象。 App 的构造函数应该是私有的,这样其他代码就不能生成第二个 App 对象。实现看起来像这样:

class App {
    private:
        App();
        App(App const&) = delete;

    public:
        static App& getApp() {
            static App theApp;
            return theApp;
        }
}

这样所有其他对象都可以通过简单地调用 App::getApp().

来引用 App 对象

首先,如评论中所述,您应该真正考虑是否要将对应用程序对象的引用传递给每个成员对象(我在这里使用术语引用来表示任何引用另一个对象,无论是 raw/smart 指针还是实际引用)。结果将是程序中的任何函数调用都可能改变程序中的任何其他状态。如果您的对象需要引用 window 来绘制某些东西,那么只需给它们引用 window 即可。

其次,您不应在此处使用智能指针,原因有二:大多数智能指针(例如 std::unique_ptrstd::shared_ptr)表示一种拥有关系。然而,对父对象的引用恰恰相反。其次,据我了解你的程序设计,你的主要应用程序对象的生命周期将 - 通过设计 - 超过你程序中任何其他对象的生命周期,所以你不必担心生命周期问题。

然后是关于指针与引用的问题:一般来说,由于您的应用程序的生命周期将超过任何其他对象的生命周期,因此使用引用没有任何坏处(除非您需要能够默认构造你的对象)。 就 "good" 软件设计而言,你应该问自己每个 class,那个 class 是否有意义,而不是参考主应用程序。如果没有,请使用参考。如果是这样,请使用一个指针,您在使用它之前总是检查 nullptr

最后:如果您确定,您的大多数对象确实需要该引用,并且您的程序逻辑是这样的,即只能有一个应用程序,那么您可以考虑将其实现为单例。虽然我不是它们的忠实粉丝,但它们并不比将引用传递给程序中的每个对象更糟糕。另一方面,当某些对象仅包含对 "pass it on" 的引用但不单独使用它时,它们有时会简化您的代码。