Qt 代码问题可能与一般 C++ 有关

Posted

技术标签:

【中文标题】Qt 代码问题可能与一般 C++ 有关【英文标题】:Qt code questions perhaps pertaining to C++ in general 【发布时间】:2014-05-17 02:39:17 【问题描述】:

我最近开始使用 Qt 框架,并意识到我可能不太了解 C++ 的语法。以在 Qt 中启动 Widget 项目时作为基础给出的这段代码为例。

MainWindow::MainWindow(QWidget *parent) :      
    QMainWindow(parent),                       
    ui(new Ui::MainWindow)

    ui->setupUi(this);


MainWindow::~MainWindow()

    delete ui;

其中MainWindow 类定义为:

namespace Ui 
    class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
;

类声明

通过这个,我可以看到创建了一个新的命名空间Ui。我认为这是一种避免与其他用户实现的类发生命名冲突的实现工作。

下面是一个新的类定义;它继承了QMainWindow,所以我们实际上是在创建一个自定义窗口对象。

Q_OBJECT 显然是一个允许用户在类定义中使用信号和槽的宏,但我现在并不太担心该代码。

我们将构造函数定义为explicit,从而禁止此类类型的任何隐式转换。还显示了一个析构函数。

在私有访问中,我们查看Ui 命名空间并创建一个MainWindow 指针。

类定义

我们正在使用我看到的初始化列表,但我在这里迷路了。我看到这个小部件的父级有一个默认参数 NULL (或 0 ),但是如果一个类固有另一个类,为什么必须显式调用所述继承类的构造函数?那就是:

class A 


class B : public A 


B testObject; 

这不会自动在堆栈上分配足够的内存来包含 A 类和 B 类吗?为什么上面显示的 Qt 代码在其自己的构造函数中调用继承类的构造函数?

继续初始化列表的第二个参数,我必须说我对这里使用的语法感到困惑。为什么我们有一个指向QMainWindow 的指针,我们通过调用QMainWindow 的构造函数并进一步调用new 来初始化它,从而创建它自己的一个实例?这种初始化方法似乎是循环的。

然后我们调用 setupUi 函数并传递 this 对象进行初始化。

最后,在析构函数中,我们简单地释放与MainWindow 关联的内存。

最后一个问题,如果创建了一个额外的对象,比如QPushButton,软件会自动释放与这些对象相关联的内存,还是必须将其与delete ui 一起包含在析构函数中?我还没有看到实际执行此操作的教程,因此我不确定该框架是否设计为可以为您处理。

我知道这里很少有直接的问题,但我对每个陈述的逻辑是否有任何缺陷?

tl;dr,跳到类定义下的第一个和第二个项目符号

【问题讨论】:

我的印象是在编译时会添加一个默认构造函数来初始化基础。 QMainWindow 继承的类呢?我知道类可能只调用其上一层的构造函数,但除非QMainWindow 的继承类有一些“包罗万象”的构造函数,否则我们会遇到一些麻烦。另外,谢谢你的收获! 【参考方案1】:

请注意,您不应该在一个问题中问这么多子问题,但无论如何我都会尝试回答您的问题...

这不会自动在堆栈上分配足够的内存来容纳 A 类和 B 类吗?

它为基类分配内存,是的。

为什么上面显示的 Qt 代码在其自己的构造函数中调用继承类的构造函数?

因为这就是 C++ 继承的工作原理。在这种情况下,您需要显式初始化基类它可能隐含在具有默认构造函数的理想中,但您甚至没有在这里使用它,这很好。

为什么我们有一个指向 QMainWindow 的指针,我们通过调用 QMainWindow 的构造函数并进一步调用 new 从而创建它自己的实例来初始化它?这种初始化方法似乎是循环的。

正如您在开始时所解释的,您有两个单独的 MainWindows,一个由 Qt 设计器生成,一个在您的代码中实现类,因此您提到了命名空间。

作为最后一个问题,如果创建了一个额外的对象,比如 QPushButton,软件是否会自动释放与这些对象关联的内存,还是必须将其与 delete ui 一起包含在析构函数中?我还没有看到真正做到这一点的教程,所以我不确定这个框架是否被设计成可以为你处理。

如果你在堆栈上分配它,则没有必要,因为它会在超出范围时自动销毁。如果您在堆上分配它,在 Qt 世界中,您将父级指定为构造函数的参数,以便在删除父级时自动删除它。这是由 Qt parent-child hierarchy and mechanism 为您透明地完成的。这就是为什么您通常在示例中看不到显式删除的原因。

【讨论】:

很好的解释。我仍然不确定您在帖子中回答的第三个问题。当我第一次在 Qt 中看到这个并编辑代码以使用它而不是上面显示的内容时,我感到很困惑:ui = new Ui::MainWindow;(在它当前所在的块之外)。这对我来说完全有意义。我知道我们需要为这个对象分配堆,但是通过调用 new 来调用 MainWindow 的构造函数来为自己分配内存是循环的并且让我感到困惑。构造函数甚至会将什么作为参数? MainWindow(MainWindow*)? @sherrellbc:这里没有循环的东西。 new Ui::MainWindowUi 命名空间中的 UI 类,而 MainWindow::MainWindowUi 命名空间外部 的 MainWindow 类。您可以找到有关 C++ 命名空间in here 的更多信息。

以上是关于Qt 代码问题可能与一般 C++ 有关的主要内容,如果未能解决你的问题,请参考以下文章

Qt Quick - 如何仅通过 c++ 代码与 qml 属性交互

不允许 C++ 异常

Qt 与 WinRT C++ 构建问题

使用 Qt、Wt 或 NaCl 构建框架?

Qt 小部件的命名约定

如何混合 C++ Qt 对象和 Qt Jambi 对象