This commit is contained in:
1AoB 2024-04-21 01:26:16 +08:00
parent f434569f7d
commit 45762d8956
2 changed files with 248 additions and 25 deletions

View File

@ -17,19 +17,113 @@ This article offers a sample of basic Markdown.
# 正文开始
1.struct和class的区别
在线编程工具:
2.值传递,地址传递,引用传递(拷贝)的区别
https://www.bejson.com/runcode/c740/
4.指针是几个字节?
5.static关键字
6.虚函数指针,虚函数表
sizeof(空类) = 1;
7.多态
静态成员变量和成员函数都不占类的大小(sizeof),也就是说静态成员变量和成员函数都不属于类
8.编译器如何知道你是进行的函数重载
```
继承下面说了
封装:将变量设置为protected或者provate,限制这些变量在类外的直接访问,我们可以使用get常量函数来完成对这个变量的封装
protected:当一个成员被定义为protected类型时仅能在类内、友元和派类访问。
private:当一个成员被定义为private类型时仅能在类内、友元访问。
多态下面说了
```
## 1.struct和class的区别
首先,class是cpp独有的,c语言里面没有,
然后就是在cpp中,class的默认访问权限是private,而struct是public;
还有就是class默认都是私有继承,而sruct默认是公有继承.
最后一点是,在语法上的区别,你使用cpp中 ,
不管是struct还是class,都可以直接使用类名.
在c语言中,要么写 struct A a;(带上struct),要么你用typedef struct A A;一下
涉及知识:https://blog.csdn.net/weixin_52668597/article/details/136666085?spm=1001.2014.3001.5501
补充:公有继承,保护继承与私有继承下,类内的元素的权限变化:
- 公有继承:原来啥权限就还是啥权限,一点不变
- 保护继承:原来公有变保护,其他两个->原来啥权限就还是啥权限
- 私有继承:原来公有变私有,原来保护变私有,原来私有还是私有
## 2.值传递,地址传递,引用传递(拷贝)的区别
值传递你无法在函数中改变这个变量的值
地址传递和引用你可以在函数中改变这个变量的值
值传递相当于是你建立了一个副本,你是你,他是他,你的改变无法影响到他,他的改变无法影响到你.
地址传递的话,传进去的就是本人了,此时修改地址上的数据会影响到原始数据.
而引用传递相当于是给该变量取的别名,相当于是一个大名一个小名比如鲁迅和周树人,本质上还是一个人,所以改变引用传递的变量也可以改变变量的原始数据
## 4.指针是几个字节?
64位系统是8字节
32位系统是4字节
## 5.static关键字
static的用法分为静态变量与静态函数
静态变量将变量限定在当前文件下,且生命周期和该文件运行的周期一样长.
然后再细分就是局部静态变量与全局静态变量:局部静态变量被限定在一个代码块内(一般是一个函数),而全局静态变量只要是在这个文件内,都可以访问.
再者就是静态函数了,<font color=red>静态成员函数只能访问静态成员变量</font>
然后就是,类中的静态成员变量并不属于这个类,你用sizeof去算,他不算这个类的大小
涉及知识:cpp编译单元 https://blog.csdn.net/weixin_52668597/article/details/137575061?spm=1001.2014.3001.5501
## 6.虚函数指针,虚函数表
涉及知识:https://blog.csdn.net/weixin_52668597/article/details/137447982?spm=1001.2014.3001.5501
只要你在类中写了一个虚函数,那么就会产生一个虚函数表.
而且不管你写多少个虚函数,这些虚函数在类中所占的内存就只有8个字节,而占的这八个字节就是虚函数指针,也就是说,这些虚函数都放在一个数组中,这个数组就是虚函数表
## 7.多态
涉及知识:https://blog.csdn.net/weixin_52668597/article/details/137447982?spm=1001.2014.3001.5501
多态其实就是 父类指针指向子类对象,如果子类重写了父类的方法,那么这个父类指针就会呈现出不同的现象
## 8.编译器如何知道你是进行的函数重载
答:函数重载,它允许在同一个作用域中定义多个同名函数,但这些函数的<font color=red>参数列表或类型</font>必须不同。在调用这些函数时,编译器会根据传递给<font color=red>函数的参数的数量、类型或顺序</font>来确定要调用的具体函数版本。
@ -41,7 +135,7 @@ This article offers a sample of basic Markdown.
9.构造,析构的顺序
## 9.构造,析构的顺序
在C++中,对象的构造和析构顺序
@ -80,9 +174,48 @@ Child::fun()
10.stlvector、list、Map的区别
## 10.stlvector、list、Map的区别
11.智能指针
vector:底层是一个动态数组,可以通过下标进行快速随机访问,占据连续的内存,在不扩容的情况下,在尾部增删很快.在扩容的情况下,需要先开辟原来容器大小的1.5倍,再将原数据拷贝到新的内存,最后在释放原内存
list:是一个双向链表,他虽然也可以用下标访问,但是那是因为他重载了中括号运算符,他访问一个元素的复杂度是o(n),他的内存是不连续的,节点之间通过指针连接.他唯一的优势是可以快速的在任意位置进行增删,但前提是先经过o(n)的复杂度找到这个位置
Map:是一个键值对,类似于json那种结构,底层是红黑树实现.
每个键都是唯一的(键和值可以为null,但是键只能出现一次),
map在插入好删除时会自动排序,他对元素的访问、插入和删除操作,这些操作的时间复杂度通常是对数时间(即`O(log n)`)。
```cpp
#include<iostream>
#include<map>
using namespace std;
class A{};
int main()
{
map<A*,int> m1,m2;
m1[nullptr] = 1;
A *a = new A();
m2[a] = 2;
printf("%d,%d",m1[nullptr],m2[a]);
map<A*,A*> m3;
m3[nullptr] = nullptr;
return 0;
}
```
## 11.智能指针
智能指针有auto_ptrshare_ptrunique_ptr还有shared_ptr
@ -109,11 +242,17 @@ auto_ptr是C++98中引入的第一个智能指针但是由于他的不安全
12.项目中如何保证线程安全?
## 12.项目中如何保证线程安全?(如何避免死锁)
13.死
加锁:**互斥锁**,**读写锁**,cpp中特有的智能
14.多线程中多个信号与主线程
## 13.死锁
死锁产生的条件:
![1713633820870](图片/1713633820870.png)
## 14.多线程中多个信号与主线程
主线程一般是负责控制和协调其他线程的任务。比如说我这个共享单车项目中的服务器,他的主线程主要是负责监听客户端的连接,一旦有客户端来进行连接,我们就会把这个客户端通过libevent变成一个事件,并把他加入到事件集合中去,然后由其他线程来监听该客户端的读写事件,并通过轮询的方式拿到线程池中的一个线程,然后由这个线程通过调用它自己的回调函数来处理这个读写事件.相当于主线程就是是负责统筹规划的,他只复制监听客户端,剩下的交给其他线程.
@ -127,35 +266,119 @@ auto_ptr是C++98中引入的第一个智能指针但是由于他的不安全
常见模式有:
1. **条件变量Condition Variables**:相当于是一种基于互斥锁的线程间同步机制,通常情况下是和锁一起使用的。主线程可以使用条件变量来等待特定的条件达成,而其他线程则可以通过发送信号来通知主线程条件的改变。一旦条件满足,主线程就会被唤醒并继续执行。
1). **条件变量Condition Variables**:相当于是一种基于互斥锁的线程间同步机制,通常情况下是和锁一起使用的。主线程可以使用条件变量来等待特定的条件达成,而其他线程则可以通过发送信号来通知主线程条件的改变。一旦条件满足,主线程就会被唤醒并继续执行。
2. **事件Events**:事件也是一种用于线程间同步的通信机制,通常用于向其他线程发出信号以触发特定事件的发生,然后执行事件的回调函数。主线程可以等待某个事件的发生,其他线程可以通过发送信号来触发该事件。
2). **事件Events**:事件也是一种用于线程间同步的通信机制,通常用于向其他线程发出信号以触发特定事件的发生,然后执行事件的回调函数。主线程可以等待某个事件的发生,其他线程可以通过发送信号来触发该事件。
3. **信号量Semaphores**
3). **信号量Semaphores**
信号量维护一个计数器表示可用资源的数量。线程可以通过请求等待和释放发信号操作来获取和释放资源。当计数器为正时线程可以继续执行否则线程会被阻塞直到资源可用。就是我们常说的那个操作系统pv操作经常用来解决“生产者消费者的问腿”
信号量维护一个计数器表示可用资源的数量。线程可以通过请求等待和释放发信号操作来获取和释放资源。当计数器为正时线程可以继续执行否则线程会被阻塞直到资源可用。就是我们常说的那个操作系统pv操作经常用来解决“生产者消费者的问题”,当然信号量也是可以的
伪代码:
```cpp
待补充。。。
生产者和消费者都可以有很多个
情况有三种:
1.队列已满,生产者停止生产商品 -> 生产者wait条件变量
2.队列为空,消费者无商品可取 -> 消费者wait条件变量
3.队列不满但非空,生产者正常生产商品,消费者正常取商品
#include "需要的头文件"
//wait()-> P()操作 --
//signal()-> V()操作 ++
typedef struct{
int value; //剩余资源数
struct process *list;//等待队列
} semaphore;
semaphore empty,full;//空位和产品的数量 空位数+产品数=最大容量
Mutex mutex1,mutex2;//两个互斥锁
//申请使用资源
void wait(semaphore s)
{
s.value --;
if(s.value < 0)//剪完1后,可能等于0(表示资源刚好用完,但是够用,所以不阻塞),也可能<0(资源早就用完了,再减一就没得用了,所以要阻塞)
{
block(s.list);
}
}
//使用完释放资源
void signal(semaphore s)
{
s.value ++;
if(s.value <= 0)//刚释放完一个资源(也就是说现在有一个资源可用),发现资源数==0,说明说明之前是<0的,表示队列已经阻塞了;如果发现资源数<0,那就更不用说了,肯定有消费者在等待
{
wakeup(s.list);
}
}
// 生产者函数
void producer() {
while (1) {
produce();//生产1个东西
wait(empty);//空位减1个
wait(mutex1);//上锁
array[空位] = 产品;//给一个空位放产品
signal(mutex1);//解锁
signal(full);//产品数+1
}
}
// 消费者函数
void consumer() {
while (1) {
wait(full);//产品数-1
wait(mutex2);//上锁
array[产品数] = null;//拿走一个产品
signal(mutex2);//解锁
signal(empty);//空位+1
comsum();//消费这个产品
}
}
int main() {
std::thread prod(producer);
std::thread cons(consumer);
prod.join();
cons.join();
return 0;
}
```
```
信号量Semaphore
信号量是一种用于控制对共享资源的访问的同步机制。它通常用于实现进程或线程间的协调。信号量主要包含两种操作wait()或称为P()操作)和 signal()或称为V()操作。wait()操作会减少信号量的计数如果结果为负数则线程会阻塞。signal()操作会增加信号量的计数,如果有线程正在阻塞,它会被唤醒。
```
4. **消息队列Message Queues**:主线程可以通过发送消息到队列中来通知其他线程,而其他线程则可以从队列中接收消息并执行相应的操作。
4). **消息队列Message Queues**:主线程可以通过发送消息到队列中来通知其他线程,而其他线程则可以从队列中接收消息并执行相应的操作。
15.qt信号槽中有第五个参数有了解过吗
信号槽中有第五个参数支持qt中,信号与槽进行跨跨线程通信,他是一个枚举值,
默认是自动连接,也比较智能,如果信号与槽是在同一个线程,就直接调用槽函数,如果不在同一个线程,会自动使用QueuedConnection.
然后支持多线程的枚举值其实有两个,一个是Queued Connection,另一个是BlockingQueuedConnection,这两个支持信号与槽的异步通信,唯一的区别是:
Queued Connection是异步非阻塞的BlockingQueuedConnection是异步阻塞的,然后非阻塞是运行后直接返回,阻塞是运行结束后才返回.
Queued Connection用的比较多,他可以保证槽函数的调用是在接收者的线程中进行的,所以就不会有多个线程同时访问槽函数中的共享资源的情况发生(除非槽函数内部又进行了不安全的跨线程操作),这样就避免线程竞争,避免了线程安全的问题。

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB