前言
Qt 是 C++ 一个最为流行的开发框架,初学 Qt 时,如果 C++ 的基本功不够,对于 Qt 中的一些代码可能不能理解。
例如下方代码:使用 Qt Creator 新建带有 MainWindow 的默认 GUI 工程
- mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
- mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
解析
解析一
在 mainwindow.h 中有这么一句 namespace Ui { class MainWindow; }
,这是一个类型声明
其中,类 MainWindow
可以追溯到 ui_mainwindow.h,而 ui_mainwindow.h 是 Qt Designer 根据 mainwindow.ui 文件自动生成的。
在 ui_mainwindow.h 声明并实现了类 Ui_MainWindow
,文件结尾在命名空间 Ui 中声明了类 MainWindow
并让其继承自类 Ui_mainWindow
回到 mainwindow.h,namespace Ui { class MainWindow; }
的作用就是提前申明这个数据类型存在,告诉编译器在其他文件中已经定义了类 MainWindow
,下方的代码使用了这个 MainWindow
不要报错,等到编译的时候可以正常找到!
>> 这样做的目的: 提高编译速度和减少编译依赖
缺点是不会对类型进行检查,如果敲错了名字一样报错,需要程序员自行确认前置声明是正确存在的
解析二
在 mainwindow.h 中 namespace Ui { class MainWindow; }
的上下还有 Qt 的宏 QT_BEGIN_NAMESPACE 和 QT_END_NAMESPACE
深入这个宏,在 qglobal.h 中就会看到如下代码:
# define QT_BEGIN_NAMESPACE namespace QT_NAMESPACE {
# define QT_END_NAMESPACE }
即如果定义了以下内容
QT_BEGIN_NAMESPACE
class QAction;
class QMenu;
class QPlainTextEdit;
QT_END_NAMESPACE
那么在编译时就会变成
namespace QT_NAMESPACE
{
class QAction;
class QMenu;
class QPlainTextEdit;
}
而 QT_NAMESPACE 是 Qt 自定定义的命名空间
因此它们的作用是将 Qt 框架中的所有类、函数、变量等都放到一个名为 Qt 的命名空间中,避免与其他命名空间中的同名实体发生冲突。所说的 Qt 框架中的类,就是例如 QObject、QWidget、QMainWindow、QPushButton 等。
但 Ui::MainWindow
是一个由 Qt 的用户界面设计器自动生成的类,用于描述主窗口的界面。这个类并不是 Qt 框架中的类,而是在使用 Qt Designer 时自动生成的。因此,它并不属于 Qt 命名空间,也不需要加上命名空间前缀 Qt::
然而我们在使用 QPushButton、QObject 时也不加 Qt:: 的原因是,在使用 QPushButton、QObject 时,我们会包含其头文件 <QPushButton>
、<QObject>
,深入进去就会发现,其类的实现就是在 QT_BEGIN_NAMESPACE 和 QT_END_NAMESPACE 之中,因此,在使用的时候就已经在 Qt 命名空间下了!但是使用变量的时候需要加上 Qt::,例如 Qt::Alignment
因此使用 QT_BEGIN_NAMESPACE 和 QT_END_NAMESPACE 的好处是,将 Qt 框架下内置的类、函数、变量放在 Qt 命名空间下,与用户自定义的类、函数、变量处于不同的命名空间,这样就避免了同名冲突。
解析三
在 mainwindow.h 中还有这么一句 Ui::MainWindow *ui;
,前面我们已经知道 Ui::MainWindow
是 Qt Designer 根据 mainwindow.ui 文件自动生成的 ui_mainwindow.h 中的类,其中包含了各种通过可视化交互操作添置的 UI 组件。
在 mainwindow.h 中将 Ui::MainWindow
作为成员变量,目的是通过该变量(指针) ui 去操作 mainwindow.ui 中的 UI 组件。
总结
- 推荐使用前置声明,尽量避免直接包含对应头文件
- 自定义类、函数和变量的名字时,不要和 Qt 框架内置的类、函数、变量重名