当前位置: 首页 > news >正文

QT入门学习(二)---继承关系、访问控制和变量定义

一:继承关系

1.1 基本继承语法

class 子类 : public 父类 {// 子类定义
};

1.public 表示继承方式(还有 protected 和 private,但 Qt 中通常用 public)。

2.子类会继承父类的所有 public 和 protected 成员。

3.子类可以重写(override)父类的虚函数。

1.2 QT的典型继承链

这里我只讲OBJECT继承链

QObject
├── QWidget
│   ├── QAbstractButton
│   │   ├── QPushButton
│   │   ├── QCheckBox
│   │   └── QRadioButton
│   ├── QLineEdit
│   ├── QLabel
│   ├── QComboBox
│   ├── QGroupBox
│   └── QFrame
│       ├── QSplitter
│       ├── QScrollArea
│       └── QToolBox
├── QThread
├── QTimer
├── QAbstractItemModel
└── QIODevice

1.2.1 QObject

QObject是所有对象的基类,作为根节点。

QWidget、QThread、QTimer 等均继承自 QObject

核心机制

                对象树:通过 parent 参数自动管理内存(如 QWidget(parent))。

                信号与槽:所有子类均可使用 connect() 实现事件通信。

示例代码

QWidget *widget = new QWidget(parent);  // parent为QObject指针
// widget的生命周期由parent管理

1.2.2 QWidget 与 UI 组件

GUI 组件的抽象:QAbstractButton → QPushButton/QCheckBox/QRadioButton

                             QLineEdit、QLabel、QComboBox 等直接继承 QWidget。

布局系统:通过 QLayout 管理子控件位置(如 QVBoxLayout::addWidget())。

示例代码

QPushButton *button = new QPushButton("Click me", this);  // this为QWidget*
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(button);  // 布局管理button的位置

1.2.3 线程模块QThread

作用

1. 实现多线程编程,将耗时操作(如文件处理、网络请求)放在后台线程,避免阻塞 UI。

2. 通过信号与槽实现线程间安全通信。

常用函数
函数名功能描述
start()启动线程,触发 run() 方法执行。
run()线程入口点,需在子类中重写(继承 QThread 方式)。
quit()请求线程退出(需线程内部配合检查)。
terminate()强制终止线程(不推荐,可能导致资源泄漏)。
wait()阻塞当前线程,直到目标线程结束。
isRunning()判断线程是否正在运行。
示例代码
// 方式1:继承QThread(简单但有限制)
class WorkerThread : public QThread {Q_OBJECT
protected:void run() override {for (int i = 0; i < 100; ++i) {emit progress(i);msleep(100);  // 模拟耗时操作}}
signals:void progress(int value);
};// 使用
WorkerThread *thread = new WorkerThread(this);
connect(thread, &WorkerThread::progress, ui->progressBar, &QProgressBar::setValue);
thread->start();  // 启动线程

 1.2.4 定时器模块QTimer

1.实现周期性任务

2.基于事件循环,不会阻塞线程。

常用函数
函数名功能描述
start(int msec)启动定时器,每隔 msec 毫秒触发一次 timeout 信号。
stop()停止定时器。
setSingleShot(bool)设置是否单次触发(true 表示仅触发一次)。
isActive()判断定时器是否正在运行。
interval()返回当前定时器的间隔时间(毫秒)。
 示例代码
// 周期性定时器
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MyClass::updateStatus);
timer->start(1000);  // 每秒触发一次timeout信号// 单次延迟执行
QTimer::singleShot(3000, this, [this]() {qDebug() << "3秒后执行此代码";
});

 1.2.5 数据模型QAbstractItemModel

1.实现模型 - 视图 - 控制器(MVC)架构,将数据与显示分离。

2.支持多种视图(列表、表格、树)展示同一数据。

常用函数(需重写)
函数名功能描述
rowCount()返回模型的行数。
columnCount()返回模型的列数。
data(const QModelIndex &index, int role)返回指定索引和角色的数据(如 Qt::DisplayRole 表示显示文本)。
headerData()返回表头数据。
setData()修改模型数据(需配合 dataChanged 信号)。
 示例代码
// 自定义表格模型
class PersonModel : public QAbstractTableModel {Q_OBJECT
public:enum Columns { Name, Age, ColumnCount };int rowCount(const QModelIndex &) const override { return m_data.size(); }int columnCount(const QModelIndex &) const override { return ColumnCount; }QVariant data(const QModelIndex &index, int role) const override {if (role == Qt::DisplayRole) {const auto &person = m_data[index.row()];return (index.column() == Name) ? person.name : QString::number(person.age);}return QVariant();}void addPerson(const QString &name, int age) {beginInsertRows(QModelIndex(), rowCount(), rowCount());m_data.append({name, age});endInsertRows();}private:struct Person { QString name; int age; };QList<Person> m_data;
};// 使用
PersonModel model;
model.addPerson("Alice", 25);
QTableView *view = new QTableView();
view->setModel(&model);  // 视图自动更新

 1.2.5 I/O 操作QIODevice

1.提供统一的输入输出接口,支持文件、网络、内存等不同设备。

2.支持同步和异步操作。

常用函数
函数名功能描述
open(OpenMode mode)打开设备(如 QIODevice::ReadOnlyQIODevice::WriteOnly)。
close()关闭设备。
read(qint64 maxSize)读取最多 maxSize 字节的数据。
readAll()读取所有可用数据。
write(const QByteArray &data)写入数据。
atEnd()判断是否到达数据末尾。
bytesAvailable()返回可用字节数。
示例代码
// 文件读写
QFile file("data.txt");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {QTextStream out(&file);out << "Hello, World!\n";file.close();
}// 网络通信(TCP客户端)
QTcpSocket socket;
socket.connectToHost("127.0.0.1", 1234);
connect(&socket, &QTcpSocket::readyRead, [&]() {qDebug() << "Received:" << socket.readAll();
});
socket.write("Request data");

二:访问控制

2.1 C++ 基础访问控制符

Qt 基于 C++,因此首先需要理解 C++ 的三种基本访问控制符:

控制符含义
public所有代码均可访问(包括类外部、子类)。
protected仅类内部和子类可访问,类外部不可访问。
private仅类内部可访问,子类和类外部均不可访问。

示例代码:

class Base {
public:int publicVar;      // 公共变量,可被任何代码访问
protected:int protectedVar;   // 受保护变量,仅Base及其子类可访问
private:int privateVar;     // 私有变量,仅Base内部可访问
};class Derived : public Base {
public:void accessMembers() {publicVar = 1;        // 合法:public成员可被任何代码访问protectedVar = 2;     // 合法:子类可访问protected成员// privateVar = 3;    // 非法:子类无法访问父类的private成员}
};

2.2 Qt 特有的访问控制机制

1. Q_OBJECT 宏与元对象系统

作用Q_OBJECT 宏使类支持信号与槽、属性系统和元对象反射。

访问限制所有使用 Q_OBJECT 的类必须继承自 QObject,且必须在头文件中声明

示例代码
class MyClass : public QObject {Q_OBJECT  // 必须包含此宏
public:explicit MyClass(QObject *parent = nullptr);
signals:void mySignal();  // 信号默认是protected的
public slots:void mySlot();    // 槽函数可设置为public/protected/private
};
2. 信号的访问控制

默认权限信号默认是 protected 的,只能通过 emit 语句在类内部或子类中触发

设计意图:防止外部代码直接触发信号,确保事件流的可控性。

示例代码
class Button : public QPushButton {Q_OBJECT
public:void fakeClick() {// emit clicked();  // 非法:信号是protected的,不能直接调用click();  // 合法:调用父类的public方法,该方法内部会emit clicked()}
};

3. 属性系统的访问控制(Q_PROPERTY)

语法
Q_PROPERTY(type name READ read WRITE write NOTIFY notify)

1.READ 方法必须是 public 的。

2.WRITE 方法(如果有)必须是 public 的。

3.NOTIFY 信号必须是 protected 的(由 Qt 自动处理)。

示例代码
class Person : public QObject {Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
public:explicit Person(QObject *parent = nullptr);QString name() const { return m_name; }  // READ方法必须publicvoid setName(const QString &name) {      // WRITE方法必须publicif (m_name != name) {m_name = name;emit nameChanged(name);}}signals:void nameChanged(const QString &name);  // NOTIFY信号默认protectedprivate:QString m_name;
};

4. 事件处理函数的访问控制

1.常见事件函数paintEvent()mousePressEvent() 等默认是 protected 的。

2.设计意图:鼓励子类重写这些函数,而不是从外部直接调用。

示例代码
class CustomWidget : public QWidget {Q_OBJECT
protected:void paintEvent(QPaintEvent *event) override {// 自定义绘制逻辑QPainter painter(this);painter.drawText(rect(), "Custom Text");QWidget::paintEvent(event);  // 调用父类实现}
};

2.3 继承与访问控制

1. 继承方式对访问权限的影响

继承方式基类的 public 成员基类的 protected 成员基类的 private 成员
public仍为 public仍为 protected不可访问
protected变为 protected变为 protected不可访问
private变为 private变为 private不可访问
 示例代码
class Base {
public:int pub;
protected:int prot;
private:int priv;
};class PublicDerived : public Base {// pub 保持 public// prot 保持 protected// priv 不可访问
};class PrivateDerived : private Base {// pub 变为 private// prot 变为 private// priv 不可访问
};

2. 子类对父类成员的访问规则

1.private 成员:子类永远无法直接访问。

2.protected 成员:子类可访问,但外部代码不可访问。

3.public 成员:子类和外部代码均可访问。

2.4 友元(Friend)机制

允许特定类或函数访问另一个类的 private 和 protected 成员。

语法
friend class FriendClass;
friend void friendFunction();
示例代码
class BankAccount {
private:double balance;
public:friend class BankManager;  // BankManager可访问所有private/protected成员friend void resetBalance(BankAccount &account);  // 友元函数
};class BankManager {
public:void adjustBalance(BankAccount &account) {account.balance = 0;  // 合法:BankManager是友元类}
};void resetBalance(BankAccount &account) {account.balance = 0;  // 合法:resetBalance是友元函数
}

2.5. 访问控制的最佳实践

1.最小权限原则

尽量将成员设为 private,仅通过 public 接口暴露必要功能。

示例代码
class Counter {
private:int m_count = 0;
public:int count() const { return m_count; }  // 只读访问void increment() { m_count++; }        // 提供受控修改
};
2.使用 protected 进行接口扩展

当需要子类重写某些功能时,将函数设为 protected virtual

示例代码
class Shape {
public:double area() const { return doCalculateArea(); }
protected:virtual double doCalculateArea() const = 0;  // 子类必须实现
};
3.避免过度使用友元

友元破坏了封装性,优先考虑通过 public 接口或继承解决问题。

三:变量定义

1. 局部变量

作用域:函数或代码块内部。

生命周期:栈上分配,离开作用域自动销毁。

示例

void MyClass::doWork() {int count = 0;                // 基本类型QString message = "Hello";    // Qt类QVector<int> numbers{1, 2, 3}; // 容器类
} // 变量在此处销毁

2. 成员变量

作用域:类的所有成员函数。

生命周期:与对象相同(堆或栈)。

访问控制:通过 public/protected/private 限制。

class MyClass : public QObject {Q_OBJECT
private:int m_counter = 0;          // 前缀 `m_` 是常见约定QString m_name;             // 默认初始化QScopedPointer<QTimer> m_timer; // 智能指针管理资源
};

3. 静态变量

作用域:类或文件内部(取决于 static 位置)。

生命周期:程序启动时创建,程序结束时销毁。

示例代码

class MyClass {
public:static int instanceCount; // 类静态变量,所有实例共享
};int MyClass::instanceCount = 0; // 必须在类外初始化// 文件静态变量(仅当前文件可见)
static QString s_appName = "MyApp";

4. Qt 特有的变量类型

1. Qt 基本数据类型

类型描述等价 C++ 类型
qint88 位有符号整数signed char
quint3232 位无符号整数unsigned int
qreal浮点数(通常为 doubledouble
QStringUnicode 字符串-
QByteArray二进制数据-
QVariant可变类型(可存储多种数据类型)-
qint64 fileSize = 1024 * 1024;  // 64位整数
QString text = "你好,Qt";      // Unicode字符串
QByteArray data = QByteArray::fromHex("48656C6C6F"); // 二进制数据

2. 容器类

优势:自动内存管理、支持隐式共享(写时复制)。

常用容器

QVector<int> numbers;        // 动态数组(连续内存)
QList<QString> names;        // 链表(适合频繁插入删除)
QMap<QString, int> ages;     // 键值对(红黑树实现,有序)
QHash<QString, int> scores;  // 哈希表(无序,查找更快)

示例代码

QVector<QString> fruits{"Apple", "Banana"};
fruits.append("Cherry");QMap<QString, int> person;
person["age"] = 30;
person["height"] = 175;

5. 内存管理与智能指针

1. 对象树管理(QObject 派生类)

机制:通过 parent 参数自动管理内存。

示例代码

QWidget *window = new QWidget(nullptr); // 顶级窗口
QPushButton *button = new QPushButton("Click", window); // button的parent是window
// 当window被删除时,button会自动被删除

2. 智能指针

QScopedPointer:独占所有权,离开作用域自动删除。

void func() {QScopedPointer<QTimer> timer(new QTimer());// timer在函数结束时自动释放
}

 QSharedPointer:共享所有权,引用计数为 0 时删除。

void shareData() {QSharedPointer<QImage> image(new QImage("image.png"));QSharedPointer<QImage> copy = image; // 共享同一对象// 当所有sharedPointer都被销毁时,QImage才会被删除
}

6. 线程安全与变量

1. 线程局部存储(QThreadStorage)

作用:为每个线程创建独立的变量副本。

示例代码

QThreadStorage<int> threadCounter;void incrementCounter() {if (!threadCounter.hasLocalData())threadCounter.setLocalData(0);threadCounter.localData()++;
} // 每个线程的counter独立计数

2. 原子变量(QAtomicInteger)

作用:提供无锁的线程安全操作。

QAtomicInteger<int> atomicCounter(0);void threadFunc() {atomicCounter.fetchAndAddOrdered(1); // 原子自增
}

7. 属性系统(Q_PROPERTY)

1. 声明属性

Q_PROPERTY(type name READ read WRITE write NOTIFY notify)

2. 通过元对象系统访问属性

Person person;
person.setProperty("name", "Alice"); // 动态设置属性
QString name = person.property("name").toString(); // 动态获取属性

8. 变量初始化与资源管理

1. 成员变量初始化

构造函数初始化列表

class MyClass {
public:MyClass() : m_value(0), m_name("") {} // 初始化列表
private:int m_value;QString m_name;
};

就地初始化(C++11+)

class MyClass {
private:int m_value = 0;         // 就地初始化QString m_name{"Name"};  // 统一初始化语法
};

2. 资源管理(RAII)

使用 QFile 自动管理文件句柄。

void writeToFile() {QFile file("data.txt");if (file.open(QIODevice::WriteOnly)) {QTextStream out(&file);out << "Hello, Qt!";} // 文件在离开作用域时自动关闭
}

相关文章:

  • 【环境搭建】Java、Python、Nodejs等开发环境搭建
  • Java垃圾回收机制详解:从原理到实践
  • ubuntu24.04 查看时区并设置Asia/Shanghai时区
  • 【Python序列化】TypeError: Object of type xxx is not JSON serializable问题的解决方案
  • Golang学习之旅
  • 单调栈(打卡)
  • 37、响应处理-【源码分析】-ReturnValueHandler原理
  • 使用API网关Kong配置反向代理和负载均衡
  • Ubuntu20.04 LTS 升级Ubuntu22.04LTS 依赖错误 系统崩溃重装 Ubuntu22.04 LTS
  • CMake指令:string(字符串操作)
  • 渊龙靶场-sql注入(数字型注入)
  • Redis部署架构详解:原理、场景与最佳实践
  • docker使用sh脚本创建容器,保持容器正常运行,异常关闭后马上重启
  • C++哈希表:冲突解决与高效查找
  • 总结:线程安全问题的原因和解决方案
  • 结构化控制语言(SCL) 与梯形图(LAD)相互转换的步骤指南
  • 16QAM在瑞利信道下的性能仿真:从理论到实践的完整解析(附完整代码)
  • PH热榜 | 2025-06-01
  • SpringBoot-Thymeleaf
  • Arch安装botw-save-state
  • 网站标题和关键词一样/评论优化
  • 做彩票网站需要什么收钱的/aso具体优化
  • 网站模板出售/哪个模板建站好
  • 去黄山旅游攻略和费用是多少/郑州网站优化外包顾问
  • 网站注册搜索引擎的目的是/网络整合营销公司
  • 建设银行网站app/百度广告代理