目录
C/C++
默认属性
C++中的堆和栈
构造、析构函数
类的继承
函数重载
新特性
指针操作
虚函数表
闭包、lambda表达式
VSC环境
C++变量的初始化
迭代
explicit
template
goto
VLA&alloca
结构体大小
C宏
逗号表达式
友员函数
mingw
嵌入式数据结构
Qt
Qt 编程规范
Qt 信号与槽
Qt 对象树
Qt Style Sheets 样式表
Qt qss
Qt 组件
QWidget
QPushButton
QRadioButton
QCheckBox
margin&padding
QHBoxLayout
QVBoxLayout
QGridLayout
QSplitter
QSpacer
QLineEdit
QDialog
QScrollArea
QTabWidget
QListWidget
综合例子
QFile
文本读写
动态创建文件
QPainter
轮播文字案例
QChart
QPropertyAnimation
Q_PROPERTY
线程的创建
Qt TCP/IP
TCP服务端
TCP客户端
Qt UDP
- 类的定义
-
默认属性
在定义类中的变量和函数不写关键字默认是private属性
-
C++中的堆和栈
-
构造、析构函数
-
类的继承
-
函数重载
-
新特性
- 变量的初始化:int x(100);
- 命名空间:namespace;
- #include <iostream> 不含.h;
- srting 数据类型;
- 构造函数可以加参数析构函数不加参数;
- :: 作用域解析运算符
- this指针:
this 只能在成员函数中使用,成员函数默认第一个参数为 T * const this。也就是一个类里面的成员了函数 int func(int p),func 的原 型在编译器看来应该是 int func(T * const this,int p)
- 重载
函数重载、运算符重载
- 继承、多态、封装
- 多态:C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数;eg:基类 Animal 声明了一个指针 animal。然后通 过基类的指针来访问 Dog 类对象与 Cat 类的对象的 run()方法,前提是基类的 run()方法必须声 明为虚函数,如果不声明为虚函数,基类的指针将访问到基类自己的 run()方法。
- 数据封装:封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受 到外界的干扰和误用,从而确保了安全
- 数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴 露接口而把具体的实现细节隐藏起来的机制
- 抽象类(接口):类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类
-
指针操作
-
虚函数表
- (*p)->f(p) :p是数据访问的起点,又是函数的第一个参数;
下面内容来自别人的笔记:
我在看时有三个疑问:
为什么要用二级指针?用一级指针不行吗?
为什么二级指针 作为函数的调用者却又作为函数的参数被传入其中?
为什么虚表结构体指针要放到第一个?
可以使用二级指针来模拟虚表,使用此方法实现复用,统一接口。 代码的关键是将一个指向虚表结构体的指针放到结构成员的第一个位置,如:
这样 结构体就会承担类似于虚表的功能。当然,也可以将这个虚表放到结构体之中(不过依旧是第一个位置),这样就可以不用二级指针了,只用一级指针即可,在这里由于虚表是否内置的变化我们已经发现了使用二级指针的第一个理由:让指针在解引用时能够正确的获取虚表中的 函数指针。
结构体包含指向虚表的指针,而不是将虚表包含在结构体中的原因是让虚表能被共享,不然每个实例都会有一份虚表的拷贝,浪费空间,初始化也会更麻烦。
我们再声明一个指针 指向 结构体,这样想要使用到 内的函数指针 便需要二次解引用操作,因此需要一个二级指针,便于使用虚表中的函数指针。我们忽略其他,从指针的层次角度出发来理解: 指向 结构体,而 结构体中又有指向 结构的指针成员,因此对于 结构体来说, 的层次与指向 结构体的二级指针相当。
在这里可能会陷入一个困惑:为什么两个指向不同类型的指针在这里能被结合在一起使用?我们看使用案例:
当 被强制类型转换成 时,使用解引用和箭头运算符便能调用 函数指针进行处理。 这是就把 当成是 的二级指针进行思考,首先对它进行解引用,变成了 的一级指针,而指针的值是指向某块内存空间的,在开头我们提到,指向虚表的指针要放在结构体成员的开头,这样,经过解引用之后的一级指针实际上的值就是虚表的地址。
实际上,指针就是地址,程序按照指针的值(地址)和指针的类型来处理内存空间中的数据。 的值被赋予了 ,程序按照 的值和类型,对指向的相应的内存空间进行处理,因为指向虚表的指针被放到了第一个,所以 先解引用出来的一级指针就是这个虚表地址。
实际上按照平常的思路是这样的:
在这里有一个重要的思维模板:
即:指针 作为函数的调用者有作为函数的参数被传入其中。 指针 p 作为参数被传入参数实际上就是相当于 指针的作用,用于使用结构体的成员变量。
那为什么 p 是指向 的二级指针,但是却能被函数使用,用作操作成员呢? 答:注意参数类型。
至于为什么虚表要放到第一个,这个疑问已经在解答为什么要用二级指针时已经想明白了。
基本思路已经说完。
闭包、lambda表达式
JS方式
C方式
VSC环境
C++变量的初始化
在构造函数中初始化
迭代
explicit 关键字用于修饰类的构造函数,用于表示构造函数是显式的。
在C++中,构造函数有时候会被自动调用进行隐式类型转换。这种情况下,构造函数的参数类型与目标类型之间存在一个合理的转换关系,编译器会自动调用该构造函数将参数转换为目标类型。这种隐式类型转换可能会导致意外的结果和编程错误。
为了避免这种隐式类型转换,可以使用 explicit 关键字来将构造函数声明为显式的。这意味着,只有在构造函数被显式调用时,才会执行构造函数,并将参数转换为目标类型。如果试图通过隐式类型转换调用显式构造函数,编译器会报错。
当构造函数被声明为显式(使用 关键字),它只能在创建对象时被显式地调用,而不能通过隐式类型转换进行调用。
当你创建一个对象时,构造函数会被自动调用。这是因为构造函数的任务是初始化对象的状态,并为对象分配必要的资源。无论是使用显式构造函数调用还是隐式构造函数调用,对象都会被正确地创建。但是,如果构造函数被声明为 ,则只能通过显式构造函数调用来创建对象。
;的声明是不正确的,因为 类的构造函数需要两个参数。当构造函数需要参数时,你需要在创建对象时为其提供必要的参数。
template <typename T>
在C++中, 是用来定义模板的语法形式。模板是一种用于创建通用代码的工具,它允许在编译时根据不同的数据类型生成不同的函数或类。
是模板参数的部分,其中 是告诉编译器后面的 是一个类型参数。 代表一个占位符,可以是任何数据类型,比如 、 或者自定义的类。通过模板参数,我们可以在使用模板时指定具体的类型。
一个简单的例子是定义一个模板函数,实现两个数字相加。可以使用 来定义一个通用的函数模板,其中 是数字类型的占位符。
然后可以使用该模板函数来计算不同类型的数字的求和,比如:
通过模板,我们可以编写更加通用和灵活的代码,而不需要为每种类型编写重复的函数。
goto
VLA&alloca
VLA:可变长度数组
alloca:用法通malloc差不多,alloca分配的内存不需要free它是在函数栈帧上扩展出来,函数返回后所分配的内存会自动释放掉。
结构体大小
【烧脑技术贴】无法回避的字节对齐问题,从八个方向深入探讨(变量对齐,栈对齐,DMA对齐,结构体成对齐,Cache, RTOS双堆栈等) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz! (armbbs.cn)
结构体内存对齐(如何计算结构体的大小)_按照结构体在内存中的对齐规则,下列结构体类型变量占用内存的大小为( ) struct te-CSDN博客
C宏
逗号表达式
逗号表达式特点,两个表达式都会执行,但结果取最后一个表达式的结果;
编程实战,简单的for循环避坑法则_哔哩哔哩_bilibili
友员函数
mingw
在 msys2 中的 mingw64 、 ucrt64 、 clang64 的区别与相同点有啥? - 知乎 (zhihu.com)
嵌入式数据结构
- 外覆式(就是不内嵌使用方便)、内嵌式
- Linux内核的链表写法,这个资料很多,这就是“内嵌式” 或 “侵入式” 的
- 在C++,Java,Rust 等等语言里面看到的 List<Blah> 之类的使用范型的数据结构,都是 “外覆式” 或者 “非侵入式” 的。
- 其实 “外覆” 和 “内嵌” 比 “侵入” 更有表达力,因为附带了额外的“如何实现非侵入”,“为何有侵入性” 的信息。
纯外覆式
- 侵入性
- Linux: C语言实现范型数据结构 - 嵌入(侵入)式链表浅谈_哔哩哔哩_bilibili
Qt 编程规范
- 文件名命名都是小写字母
- 类的名字首字母是大写,单词和单词之间首字母是大写
- class QMainWindowPrivate : public QWidgetPrivate{}
- 除了构造函数和析构函数,成员函数的首字母都是小写,单词和单词之间首字母是大写
- QMainWindowPrivate()
- dockWidgetArea()
- 变量的首字母都是小写,单词与单词之间首字母大写
- dockWidget
Qt 信号与槽
点击按键对象调用点击方法,发送给主窗口触发关闭窗口事件槽;
方法1
方法2
自定义槽函数
自定义信号与槽
- 在各自的.h中创建school和student类,在类中定义信号量与槽
- 在自的.cpp中创建构造函数,和定义槽
- 在mainwindow.h和mainwindow.cpp中,在.h创建School、Student对象,在.cpp中实例化school、school对象创建连接信号槽,并且发送信号;
- 在main.cpp中会创建MainWindow对象(它是一个屏幕),在它在构造函数中就会实现实例化school、school对象创建连接信号槽,并且发送信号;这里的信号是school发送的槽是student,在调用school发送信号后;student槽就会收到;
Qt Style Sheets 样式表
- 用图形化设置
- 用代码设置
Qt qss
- Qt Style Sheet
- 在构造函数中创建2个label
- 创建qss文件配置样式
- 在main中打开配置的qss文件并读取里面内容作用于样式
Qt 组件
QWidget
- QWidget是所以用户界面对象的基类
- 常用于做顶层小部件或者子小部件
QPushButton
- 常用的四个信号:clicked()、pressed()、released()、toggled()
toggled为切换开关 首先要使能ui->pushButton->setCheckable(true);可选中属性
QRadioButton
(单选按钮)
qss样式
知识点:多选、互斥(exclusive)、按键组、常用信号toggled
QCheckBox
知识点:三态(tristate)unchecked未选、indeterminate半选、选中;staeChanged信号
margin&padding
margin:外边距,一个控件的边框到另外一个控件的边框的距离,属于容器外部距离;
padding:内边距,自身边框到自身内部另一个容器边框的距离,属于容器内距离;
qss样式
QHBoxLayout
水平布局知识点
- spacing(间隔距离):控件与控件之间的距离
- stretch(拉伸因子系数):
- sizePolicy(大小策略) eg:Ignored忽略组件的缺省大小
将屏幕设置被水平布局实现在拉大窗口时控件大小也会随着变化
未设置前
设置后
QVBoxLayout
垂直布局
QGridLayout
网格布局
QSplitter
分裂器:即可以当做显示控件又可以当做布局
- orientation:设置方向,可设置水平或垂直方向;
- childrenCollapsible:为true时,用户可以将子部件的大小调整为0;
- opaqueResize:为false时,在拖动的时候会显示一条灰色的线条,在拖动到位并释放鼠标后再显示分割线条。默认为true,实时更新子控件大小;
QSpacer
隔离弹簧;与布局结合使用
- orientation:方向属性,可设置水平或垂直方向;
- sizeType: 大小类型,可设置好几种,如固定大小,可扩大小;
- sizeHint:缺省大小;
QLineEdit
单行文本输入框
QDialog
对话框:是QMainWindowQWidgetQDialog 三个基类中的一种
QDialog不支持设置圆角,所以以QDialog作为父对象在设置他为移除边框、设置背景透明,在里面添加QFrame;
QScrollArea
设置面板滚动视图
样式表
QTabWidget
面板切换
- 关闭tab
- 去除掉tab配合QListWidgets通过currentRowChanged实现跳转
- 默认浅色焦点
QListWidget
列表
- 添加、删除、插入项
综合例子
- 自定义一个qqitem项(类),绘制qqitem.ui
- 编写qqitem类的构造函数以及构造函数的形参
- 绘制widget.ui,主要是QListWidget控件;
- 在widget中创建几个qqitem对象,并将这些对象作为QListWidget的item添加进入
QFile
-
文本读写
文本读写流程:
- 用QFileDialog类弹出文件选择框,并返回文件路径和文件名;
- 再用QFile类读写文件
widget.ui中绘制一个文本编辑框和两个按键并设置对应的槽
- 打开文件槽用QFileDialog类弹出文件选择框,并返回文件路径和文件名;再读文件到文本编辑框显示
- 关闭文件槽,把编辑完的内容写回清空文本编辑框显示
-
动态创建文件
- 创建widget.ui,用于创建filedialog;
- 创建filedialog,用于文本输入;
- filedialog.h中声明用于返回文本编辑框内容的函数以及3个槽函数,filedialog.c定义上述函数
QPainter
画矩形、三角形、直线、圆、椭圆、文字、路径(paintEvent是一个重载函数)
轮播文字案例
通过重写paintEvent函数,配合定时器来改变文字框的位置实现移动
- widget.h
- widget.cpp
QChart
把GraphicsViewt提升为QChart类变成QChartView控件
- widget.h
- widget.cpp
QPropertyAnimation
属性动画:几何动画、颜色动画、不透明度动画
- widget.h
- widget.cpp
Q_PROPERTY
宏语法:
- 声明宏名,这里相当于吧“money”这个属性,绑定READ读函数fnReadMoneyTotal ,WRITE写函数fnSetMoney,qrealdouble类型()是读函数的返回值类型
- 声明对象再调用setProperty方法就会自动调用之前声明的宏名所设置WRITE
rich.h
rich.cpp
widget.h
widget.cpp
- 配合自定义属性动画
setStartValue会调用宏定义的方法来改变数值实现动画
rich.cpp
widget.cpp
线程的创建
创建一个继承QThread的线程类,每个线程的入口函数为run(),所以每个线程都要重写run(方法);
- widget.h
动态创建线程并销毁
- widget.cpp
Qt TCP/IP
TCP服务端
- 创建 QTcpServer * tcpServer;
- 开始监听按键的槽用于监听指定客户端的IP和端口
- 当有客户端连来连接时,服务器发出newConnection信号,创建对应的mNewConnection槽函数,在槽函数中调用tcpServer的方法,创建一个Socket每一个客户端过来连接都会创建一个Socket,再为每个Socket创建两个信号槽连接,一个用于当客户端有发送数据来接收消息,一个用于客户端连接状态的改变
- 以及一个开启/停止监听,和向客户端发送消息
- widget.h
- widget.cpp
TCP客户端
- 创建QTcpSocket * tcpSocket;
- 连接服务器按键的槽用于连接服务器的地址和端口
- tcpSocket创建两个信号槽连接,一个用于向服务器发送数据,一个用于连接状态的改变
- widget.h
- widget.cpp
Qt UDP
widget.h
widget.cpp