【问题标题】:c++ Assigning objects in object declarationc++ 在对象声明中分配对象
【发布时间】:2011-03-19 15:13:30
【问题描述】:

我来自 Java 背景,最近决定尝试“为了好玩”创建一个 C++ Qt GUI 应用程序。我一直在努力解决 Java 和 C++ 之间的许多细微差别,但我学到了很多东西。

我试图在我的 C++ 编码中尽可能地匹配“java 风格”的语法。虽然这可能是也可能不是 C++ 的“最佳实践”,但我觉得在学习保持熟悉且一致的语法时会有所帮助。 Java 语法遗留物之一是这样的:

//Java
MyObject o = new MyObject();

//C++
MyObject o = MyObject();

现在,我知道 C++ 有一个语法快捷方式:

//C++
MyObject o();

这很好,但正如我所说,我还不想使用不同的语法。一切正常,但当我尝试以下 Qt 代码时,我收到了一个惊喜:

QString filepath = "C:\\somefile";
QFile file = QFile(filepath);

并得到一个编译错误:

c:\QtSDK\Desktop\Qt\4.7.2\mingw\include/QtCore/qfile.h:195: error: 'QFile::QFile(const QFile&)' is private within this context

我阅读了 Qt 文档,发现确实没有公共构造函数 QFile::QFile(const QFile&)。在我的代码以前为其他类工作的地方,有这样一个构造函数。我可以在这里猜测并说那行:

QFile file = QFile(filepath);

实际上是在调用两个构造函数。谁能解释一下?

【问题讨论】:

  • 只是指出一件事:在 C++ 中,像“MyObject o();”这样的声明声明一个名为 o 的函数,它不接受任何参数并返回一个 MyObject。要声明一个调用默认构造函数的 MyObject,可以执行“MyObject o;”
  • @Batchy 那么使用“MyObject o”,o 是否已完全初始化?与 Java 相比令人困惑。
  • 如果MyObject 是POD ;-)

标签: java c++ qt


【解决方案1】:
//Java
MyObject o = new MyObject();

//C++
MyObject o = MyObject();

这些是不等效的。 c++ 版本创建了一个新对象,on stack,这是 java 只能对原始类型执行的操作。一旦o 超出范围,它将被破坏。上面实际发生的逻辑上是MyObject o(MyObject());(实际语法不正确)- 构造后跟复制构造。

MyObject * o = new MyObject();

这与您的 java 版本一样接近。当然,需要注意的是,在 C++ 中,您还需要 delete o; - 它不会收集垃圾。

QFile file = QFile(filepath);

这会再次在堆栈上创建一个临时 QFile,然后通过从临时文件中复制构造它来创建 file。相当于QFile file(QFile(filepath));。在你的情况下这不起作用,QFile 不允许复制构造,所以你需要通过直接构造 QFile 来避免临时,

// on stack:
QFile file(filepath);

//or in heap:
QFile * file = new QFile(filepath);

【讨论】:

  • 现在我明白发生了什么,这是有道理的。我知道堆栈和堆之间的区别,我使用 MyObject o = MyObject() 的全部目的是避免指针和堆。但是,我错误地认为我可以摆脱 QFile f = QFile(path)。谢谢。
  • 您缺少构造对象的常规方法(对您和我来说很明显,但对 Java 开发人员而言并非如此)。 QFile file("Path");
  • @Erik:现在我可以看到了。 ;-)
  • 实际上,MyObject o(MyObject()); 是一个函数 o 的声明,它返回一个 MyObject,它接受一个匿名指针,指向一个不带参数并返回一个 MyObject 的函数。
【解决方案2】:
MyObject o();

这不是任何类型的对象声明的捷径。它是一个名为 o 的函数的声明,它按值返回 MyObject。

这是最简单的对象声明。如果对象具有用户声明的构造函数,则将调用默认构造函数。

MyObject o;

对于一些基本对象类型(那些是或直接包含 POD - 普通旧数据 - 子对象并且没有用户声明的构造函数),部分或全部对象可能会被初始化。为确保此类对象的所有部分都已初始化,您可以从临时初始化的值中复制初始化。对于具有用户声明的构造函数的对象,这不是必需的。

MyObject o = MyObject();

new 仅在 C++ 中需要,其中对象需要超过创建它的范围。 new 总是返回一个指向动态分配对象的指针。在大多数生产代码中,您通常应该立即将此类对象分配给智能指针,例如 shared_ptr,以确保动态分配的对象不会泄漏。

【讨论】:

    【解决方案3】:

    当你像这样声明一个对象时:

    QFile file = QFile(filepath);
    

    首先调用带有字符串的构造函数 (QFile(filepath)),然后调用复制构造函数 (QFile(const QFile&))(通过 =)。

    Qt 决定将QFile 的复制构造函数设为私有,以防止您复制它。

    【讨论】:

      【解决方案4】:
      QFile file(filepath);
      

      可以正常工作,因为它会调用QFile(const QString&) 构造函数。

      在执行QFile file = x 时,file 对象是使用应用于x 的复制构造函数 构造的,正如编译器告诉你的那样,这里是私有的。

      MyClass c(something) 语法不是MyClass c = something 的快捷方式。第二个将始终调用复制构造函数,第一个将根据something 的类型调用合适的构造函数。

      【讨论】:

        【解决方案5】:

        是的。

        QFile file = QFile(filepath);
        

        创建并构造一个 QFile(= 右边的那个)。然后,将它分配给另一个 QFile。这会调用 QFile 上的复制构造函数,但正如错误所说,它在 QFile 中被定义为私有的,因此您编写的内容将不起作用。

        您可能想要做的是直接创建 QFile,如下所示:

        QFile file(filepath);
        

        顺便说一句,我认为您尝试使用类似 Java 的语法编写 C++ 的目标是错误的! C++、Java 或任何语言领域的程序员已经开发出用这些语言编写代码的风格,这些风格与其他语言不同,这是有充分理由的。通常原因是使用这些样式可以编写简洁的代码,避免错误和不希望的副作用。

        【讨论】:

        • 感谢您的洞察力。我意识到在现实世界中,“Javay”C++ 代码可能是一个非常糟糕的主意。在我学习 C++ 的复杂性时,它对我有帮助。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-04
        • 1970-01-01
        • 2016-07-28
        • 1970-01-01
        • 2012-11-18
        • 1970-01-01
        相关资源
        最近更新 更多