目录
第1章 简介
在 Qt 中,使用 C++ 是主要的编程语言。C++ 是一种通用的、强类型的编程语言,通过与 Qt 框架结合使用,可以轻松构建跨平台的图形用户界面(GUI)应用程序和其他类型的应用程序。
以下是 Qt 中使用 C++ 的一些方面和特点:
-
对象导向编程(OOP):C++ 是一种面向对象的编程语言,而 Qt 以面向对象的方式构建。通过使用 C++,开发人员可以利用类、继承、多态等 OOP 概念来组织和管理代码。
-
Qt 类和库:Qt 提供了丰富的类和库,用于创建 GUI 元素、处理事件、进行图形绘制、进行网络通信等。这些类和库是用 C++ 编写的,通过使用它们,开发人员可以快速构建功能强大的应用程序。
-
信号与槽机制:Qt 的信号与槽机制是通过 C++ 的特性实现的。它利用了 C++ 的函数指针和运算符重载,使得对象之间的通信变得灵活和可靠。
-
内存管理:Qt 使用了 RAII(资源获取即初始化)的内存管理技术,通过自动化对象的生命周期管理,减少了内存泄漏和资源管理的复杂性。同时,Qt 还提供了智能指针和其他内存管理工具,帮助开发人员更方便地管理内存。
-
异常处理:C++ 支持异常处理机制,而 Qt 的许多类和函数也使用了异常来处理错误和异常情况。开发人员可以使用 try-catch 块来捕获并处理这些异常。
-
C++11 和更新版本支持:Qt 对于 C++11 标准及更高版本的支持逐步提升。开发人员可以使用 C++11 的新特性,如自动类型推断、Lambda 表达式、智能指针等,以便更轻便和方便地编写 Qt 应用程序。
需要注意的是,尽管 Qt 使用的是 C++ 作为主要的编程语言,但它也对其他编程语言提供了一些支持,例如使用 QML(Qt Quick)进行声明性编程。通过 QML,开发人员可以使用 JavaScript 语言与 Qt 进行交互,并构建动态且现代的用户界面。
总之,Qt 和 C++ 的结合提供了一种强大的开发环境,使开发人员能够构建跨平台、高性能且功能丰富的应用程序。
第2章 语言特性
2.1 面向对象的封装性
int main(int argc, char *argv[])
{
QApplication a(argc, argv); //应用程序对象,管理UI主线程
QIcon icon(":/res/logo.png");
a.setWindowIcon(icon); //设置应用程序的icon
MainWindow w; //创建主窗口对象
w.show(); //展示主窗口
return a.exec(); //执行应用程序的事件处理线程
}
2.1 强大的信号和槽机制 =》对象之间通过信号进行通信
信号与槽的基本原理是:注册与回调机制!!!
2.2 可查询的设计的对象属性
2.3 时间和事件过滤器
2.4 对字符串国际化的支持
2.5 精密时间
精密的间隔驱动的定时器,使其能够优雅地整合在一个事件驱动的图形用户界面的多任务。
2.6、良好的对象组织结构 =》 类的继承
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QFont>
class MyMainWindow : public QWidget // MyMainWindow继承于QWidget对象
{
public:
MyMainWindow();
private:
QPushButton *b1;
};
2.7 Qt中处理了 野指针 的问题
使用QPointer类实现当指针所指对象被删除时讲指针置为0
2.8 灵活的动态类型转换
Qt对C++的扩展是从QObject(类似java中的java.lang.Object)开始的,称为Qt的元对象系统,这需要元对象编译器MOC的支持。Qt通过对C++的封装、扩展实现灵活的GUI编程。
2.9 构造函数
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug() << "main threadId: " << QThread::currentThreadId();
}
MainWindow::MainWindow(QWidget *parent)
{
}
MainWindows类的有参构造函数:MainWindow(QWidget *parent)
参数:
- parent:指向父窗口对象
2.10 初始化列表与对象的初始化
这段代码是一个典型的 Qt 主窗口类 MainWindow
的构造函数的实现。下面来逐行解释:
class MainWindow : public QMainWindow //继承于QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
}
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
-
MainWindow::MainWindow(QWidget *parent)
是构造函数的定义,表示MainWindow
类的构造函数,接受一个QWidget*
类型的parent
参数。parent是构造函数的参数,用于指向父窗口。
-
: 是构造函数的初始化列表。
-
: QMainWindow(parent)
表示调用MainWindow类的基类QMainWindow
类的构造函数,并将parent
参数传递给它。这样可以确保在构造MainWindow
对象时,同时构造其基类QMainWindow成员
。 -
, ui(new Ui::MainWindow)
是一个成员变量/熟悉ui的初始化语句,用于初始化名为ui
的指向Ui::MainWindow
类的指针。Ui::MainWindow
是一个自动生成的类,用于管理主窗口的用户界面布局和元素。ui用于MainWindow对象。
这段代码的目的是在构造函数中初始化主窗口对象,并创建一个 Ui::MainWindow
对象ui,用于管理用户界面相关的内容。通常在这个构造函数中,还可以执行其它初始化操作,如设置窗口标题、添加部件等。
需要注意的是,这段代码是使用 Qt 的可视化设计工具(如 Qt Creator)自动生成的。在可视化设计工具中,用户可以通过拖拽和布局来创建用户界面,然后工具会自动生成这个构造函数及相关的代码。用户可以在生成的构造函数中添加自定义的逻辑和处理代码。
构造函数的初始化列表是在构造函数的定义中使用冒号(:
)后面的部分,它用于初始化成员变量和调用基类的构造函数。
初始化列表的语法是以逗号分隔的成员初始化语句,每个成员初始化语句由成员名称、圆括号和初始化值组成。
一个典型的构造函数的初始化列表的示例如下:
ClassName::ClassName(Type1 arg1, Type2 arg2)
: member1(arg1), member2(arg2), member3()
{
// 构造函数的其他代码
}
在上面的示例中:
ClassName
表示类的名称。Type1
和Type2
是成员变量member1
和member2
的类型。arg1
和arg2
是构造函数的参数。member1(arg1)
和member2(arg2)
是成员变量初始化语句,用于将参数的值初始化给成员变量。member3()
是成员变量初始化的另一种方式,没有提供参数,则使用默认的构造函数进行初始化。
构造函数的初始化列表的作用包括:
-
初始化成员变量:通过初始化列表,可以在对象被创建时直接将初始值赋给成员变量,避免了在构造函数体内再次赋值的操作。
-
调用基类构造函数:如果当前类是派生类,初始化列表可以用来调用基类的构造函数,确保正确初始化继承自基类的成员变量。
通过使用初始化列表,可以提高代码执行效率,并确保正确和一致的对象状态初始化。特别是对于复杂的类构造函数,在初始化列表中一次性设置多个成员变量的值,可以使代码更清晰和易读。
需要注意的是,在初始化列表中的成员变量初始化顺序应与它们在类中声明的顺序一致,以避免潜在的问题。
在派生类的构造函数中,同样可以使用初始化列表来调用基类的构造函数和初始化派生类自己的成员变量。初始化列表的语法和基类构造函数的调用方式类似。
以下是一个派生类构造函数初始化列表的示例:
DerivedClassName::DerivedClassName(Type1 arg1, Type2 arg2, Type3 arg3)
: BaseClassName(arg1), member1(arg2), member2(arg3)
{
// 派生类构造函数的其他代码
}
在上面的示例中:
DerivedClassName
表示派生类的名称。Type1
、Type2
和Type3
是基类构造函数和派生类成员变量的类型。arg1
、arg2
和arg3
是构造函数的参数。BaseClassName(arg1)
是调用基类的构造函数,并将参数的值传递给它。member1(arg2)
和member2(arg3)
是派生类成员变量初始化语句,用于将参数的值初始化给成员变量。
通过初始化列表,在派生类的构造函数中可以正确地初始化基类和派生类自己的成员变量,确保对象的完整初始化。此外,如果派生类没有定义自己的成员变量,只需要调用基类的构造函数即可。
需要注意的是,派生类的构造函数会自动调用基类的默认构造函数,如果基类没有提供默认构造函数,派生类的构造函数必须在初始化列表中显式调用基类的适当构造函数。同时,派生类构造函数在初始化列表中只能调用直接基类的构造函数,不能调用间接基类的构造函数。
总而言之,派生类的初始化列表是用于初始化派生类自己的成员变量和调用基类的构造函数。通过使用初始化列表,可以保证在派生类的构造函数中正确初始化对象的各个部分,确保对象被正确创建和初始化。
2.11 override
在C++中,override
是一个关键字,用于在派生类中明确地指示对基类虚函数的覆盖。
通过使用override
关键字,可以提高代码的可读性和可维护性,以确保派生类正确地覆盖了基类的虚函数。
使用override
的语法如下:
class Base {
public:
virtual void myFunction();
};
class Derived : public Base {
public:
void myFunction() override; //头文件中声明,需要覆盖,在源文件中,需要定义实体函数
};
在上面的示例中,Base
类声明了一个虚函数myFunction()
。在派生类Derived
中,使用override
关键字明确地指示了对基类虚函数的覆盖。这样,在派生类中如果没有正确覆盖基类的虚函数,编译器将报错。
当派生类中使用override
关键字时,编译器将会检查该函数的签名与基类的虚函数的签名是否匹配。如果签名不匹配(如参数列表、返回类型不同等),编译器会报错。
使用override
关键字可以提供更强的类型检查,并帮助开发人员在派生类中正确地覆盖基类的虚函数。它可以避免因为意外的错误或者拼写错误导致的虚函数覆盖失败。
需要注意的是,override
关键字只适用于覆盖基类中的虚函数,而不适用于非虚函数或静态函数的重写。在重写非虚函数或静态函数时,不需要使用override
关键字。
通过使用override
关键字,可以提高代码的可靠性和可维护性,帮助开发人员避免一些常见的错误,并使程序的行为更加可预测。