第二次 的面试题目 (自闭!!)

1.qt 调试时遇见过的报错信息。

       1.遇到过 最常见的是  没有加头文件  , 

        2.未定义错误


2.在linux上使用过gdb吗? 怎么使用。

什么是GDB,能干啥?
 gdb是GNU开源组织发布的一个强大的Linux下的程序调试工具。

 一般来说,GDB主要帮助你完成下面四个方面的功能:

1、启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。

2、可让被调试的程序在你所指定的调置的断点处停住。(断点可以是条件表达式)

3、当程序被停住时,可以检查此时你的程序中所发生的事。

4、你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG。
.GDB调试的对象
 GDB主要来调试C/C++语言写的程序,当然也就可以调试其他语言程序。这里我们只说C/C++(其他语言我也不会呀)
GDB调试一定要是可执行文件而不是.c文件
要用gcc进行编译,具体的命令如下:

(gdb)help:查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h

(gdb)run:重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r

(gdb)start:单步执行,运行程序,停在第一执行语句

(gdb)list:查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l

(gdb)set:设置变量的值

(gdb)next:单步调试(逐过程,函数直接执行),简写n

(gdb)step:单步调试(逐语句:跳入自定义函数内部执行),简写s

(gdb)backtrace:查看函数的调用的栈帧和层级关系,简写bt

(gdb)frame:切换函数的栈帧,简写f

(gdb)info:查看函数内部局部变量的数值,简写i

(gdb)finish:结束当前函数,返回到函数调用点

(gdb)continue:继续运行,简写c

(gdb)print:打印值及地址,简写p

(gdb)quit:退出gdb,简写q

(gdb)break+num:在第num行设置断点,简写b

(gdb)info breakpoints:查看当前设置的所有断点

(gdb)delete breakpoints num:删除第num个断点,简写d

(gdb)display:追踪查看具体变量值

(gdb)undisplay:取消追踪观察变量

(gdb)watch:被设置观察点的变量发生修改时,打印显示

(gdb)i watch:显示观察点

(gdb)enable breakpoints:启用断点

(gdb)disable breakpoints:禁用断点

(gdb)x:查看内存x/20xw 显示20个单元,16进制,4字节每单元

(gdb)run argv[1] argv[2]:调试时命令行传参


3.什么情况下使用线程池和内存池。怎么实现的。

1、线程池的概念
  服务器程序利用线程技术响应客户请求已经司空见惯,但是线程的使用是有待优化和处理的。单线程执行并不是一个高效的方式,这个时候可能就要考虑高并发,多线程等方式。线程池也是线程优化的一种方式。

  在面向对象的过程中,对象的创建和销毁是非常占资源的,每创建一个对象都要获取内存资源以及其他一些资源。这就产生了“池化技术”。

【线程池如何提高服务器程序的性能?】

T1 = 创建线程;
T2 = 执行线程 包括访问共享数据、线程同步等;
T3 = 销毁线程;
T = T1 + T2 + T3。
  单线程的情况下,系统花大量的时间再T1、T3阶段。我们要采取最优的措施,减少T1和T3的系统开销。线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。

线程池的组成部分
(1) 线程管理器:用于创建并管理线程池。

(2)工作线程:线程池中实际执行任务的线程。在初始化线程时会预先创建好固定数目的线程在池中,这些初始化的线程一般处于空闲状态。

(3)任务接口:每个任务必须实现的接口。当线程池的任务队列中有可执行任务时,被空间的工作线程调去执行(线程的闲与忙的状态是通过互斥量实现的),把任务抽象出来形成一个接口,可以做到线程池与具体的任务无关。

(4)任务队列:用来存放没有处理的任务。提供一种缓冲机制。实现这种结构有很多方法,常用的有队列和链表结构。

3、线程池的流程
1. 调用pthread_create()创建若干线程,置入线程池。

2. 调用pthread_cond_wait()等待任务队列不为空的条件上;任务到达时,从线程池取空闲线程处理任务队列中的任务;调用pthread_cond_signal()通知可以有新任务添加进来。

3. 调用pthread_cond_wait()等待任务队列不为满的条件上;向任务队列中添加任务;调用pthread_cond_signal()通知线程池中的线程去处理任务。

4. 调用pthread_detach()销毁线程池中的线程。

线程池的应用
【线程池适用于】:

需要大量的线程来完成任务,且完成任务的时间比较短。web服务器完成网页请求这样的任务,使用线程池技术是非常合适的。 因为单个任务小,而任务数量巨大,一个热门网站的点击次数会很多。

对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。

接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。

【线程池不适用于】:

如果需要使一个任务具有特定优先级。

如果具有可能会长时间运行(并因此阻塞其他任务)的任务。

如果需要将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)。

如果需要永久标识来标识和控制线程,比如想使用专用线程来终止该线程,将其挂起或按名称发现它

内存池的概念


  内存池(Memory Pool)是一种内存分配方式。通常我们习惯直接使用new、malloc等API申请内存,这样做的缺点在于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。

  内存池则是在真正使用内存之前,预先申请分配一定数量、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是,使得内存分配效率得到提升。

2、内存池的流程和设计
1. 先申请一块连续的内存空间,该段内存空间能够容纳一定数量的对象。

2. 每个对象连同一个指向下一个对象的指针一起构成一个内存节点(Memory Node)。各个空闲的内存节点通过指针形成一个链表,链表的每一个内存节点都是一块可供分配的内存空间。

3. 某个内存节点一旦分配出去,从空闲内存节点链表中去除。

4. 一旦释放了某个内存节点的空间,又将该节点重新加入空闲内存节点链表。

5. 如果一个内存块的所有内存节点分配完毕,若程序继续申请新的对象空间,则会再次申请一个内存块来容纳新的对象。新申请的内存块会加入内存块链表中。


 

内存池的特点
针对特殊情况,例如需要频繁分配释放固定大小的内存对象时,不需要复杂的分配算法和多线程保护。也不需要维护内存空闲表的额外开销,从而获得较高的性能。

由于开辟一定数量的连续内存空间作为内存池块,因而一定程度上提高了程序局部性,提升了程序性能。

比较容易控制页边界对齐和内存字节对齐,没有内存碎片的问题。

当需要分配管理的内存在100M一下的时候,采用内存池会节省大量的时间,否则会耗费更多的时间。内存池可以防止更多的内存碎片的产生。更方便于管理内存。


4.怎么使用git管理代码。

三个链接

关于git代码管理的详细操作流程_穿堂风anony的博客-CSDN博客_git代码管理流程

【Git】手把手教你使用git管理代码 (上)_嘻咦啊写的博客-CSDN博客_git管理代码

关于git代码管理的详细操作流程_穿堂风anony的博客-CSDN博客_git代码管理流程


5.c++ 多态  虚函数  static函数和参数的使用。

一份链接

c++ 语言学习 day04 (使用 QT c++ 编译器)继承, .多继承 ,内部类,局部类,构造函数的相互调用,多态,虚函数:__She001的博客-CSDN博客_qt继承多个类


6.多个类怎么使用一个变量

纯虚函数

继承


7.linux怎么单次和永久改ip

一个链接

教你怎么在linux上永久修改IP地址_zhaidada01的博客-CSDN博客_linux永久修改ip地址


8.使用什么命令查找复制指定目录定位.so文件。

ls - *.so


9.qt线程中怎样处理和修改界面?

采用的办法是: 利用 signal/slot 机制。在 线程类中创建一个 signal (信号), 在界面管理类中 创建一个 slot (槽)。每当线程需要修改界面的时候, 就发送一个需要修改界面的信号, 界面收到这个信号以后,会调用相应的 方法(槽)来处理


10.TCP与UDP的区别?

 
TCP 的全称是Transmission Control Protocol ,传输控制协议。其首部字节为20~60字节

1.1 特点
面向连接
传输是可靠的,保证了数据的正确性和数据顺序
以字节流的形式进行传输,实际上是TCP把数据看成一连串无结构的字节流;
1.2 性能
传输效率慢
需要的资源多
1.3 应用场景
要求文件传输可靠(如文件传输、邮件传输)

1.4 步骤
TCP编程的服务器端一般步骤是:

创建一个socket,用函数socket();
设置socket属性,用函数setsockopt(); * 可选
绑定IP地址、端口等信息到socket上,用函数bind();
开启监听,用函数listen();
接收客户端上来的连接,用函数accept();
收发数据,用函数send()和recv(),或者read()和write();
关闭网络连接;
关闭监听;


TCP编程的客户端一般步骤是:

创建一个socket,用函数socket();
设置socket属性,用函数setsockopt();* 可选
绑定IP地址、端口等信息到socket上,用函数bind();* 可选
设置要连接的对方的IP地址和端口等属性;
连接服务器,用函数connect();
收发数据,用函数send()和recv(),或者read()和write();
关闭网络连接;


2. UDP
UDP 的全称是 User Datagram Protocol,用户数据报协议。由8个字节(即4个字段)组成

2.1 特点
面向无连接
传输不可靠,可能会出现丢包、UDP不能保证数据的发送顺序
以数据报文段的形式进行传输,UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用)

2.2 性能
传输效率快
需要的资源比较少
2.3 应用场景
面向数据报方式
网络数据大多为短消息
拥有大量Client
对数据安全性无特殊要求
网络负担非常重,但对响应速度要求高
要求通讯速度快(如域名转换);或者是即时通讯(语音、视频、直播等)
2.4 步骤
UDP编程的服务器端一般步骤是:

创建一个socket,用函数socket();
设置socket属性,用函数setsockopt();* 可选
绑定IP地址、端口等信息到socket上,用函数bind();
循环接收数据,用函数recvfrom();
关闭网络连接;
UDP编程的客户端一般步骤是:

创建一个socket,用函数socket();
设置socket属性,用函数setsockopt();* 可选
绑定IP地址、端口等信息到socket上,用函数bind();* 可选
设置对方的IP地址和端口等属性;
发送数据,用函数sendto();
关闭网络连接;
3. 具体
3.1 TCP
TCP是面向连接的服务。在传输数据之前必须先建立连接,数据传送介绍后需要释放连接。
TCP不提供广播或多播服务。
由于TCP要提供可靠的、面向连接的传输服务(TCP的可靠性提现在TCP在进行传递数据之前,会有三次握手来建立量额吉,而且在数据传递时,有确认、窗口、重传、拥塞控制等机制,在数据传递完后,还会端口连接用来节约系统资源),这些难以避免的操作增加了许多开销,如确认、流量控制、计时器以及连接管理等。
这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。
TCP一般用于文件传输、发送和接收邮件、远程登录等场景。
3.2 UDP
UDP在传送数据之前不需要先建立连接,远程主机在收到UDP报文以后,不需要给出任何确认。
虽然UDP不提供可靠的交付,但在某些情况下UDP确实是一种最有效的工作方式(一般用于即时通讯),比如语音、视频、直播等。
4. 区别
TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接

TCP要求的系统资源较多,UDP较少

TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付

TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)

每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

TCP首部开销20字节;UDP的首部开销小,只有8个字节

TCP的逻辑通信信道是全双工的可靠信道;UDP则是不可靠信道

5. 补充
UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务。并且它是将应用程序发来的数据在收到的那一刻,立刻按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况下,UDP也无法进行流量控制等避免网络拥塞的行为。
此外,UDP如果在传输途中出现了丢包,UDP也不负责重发。甚至当出现包的到达顺序乱掉时也没有纠正的功能。如果需要这些细节控制,那么不得不交给由采用UDP的应用程序去处理。换句话说,UDP将部分控制转移到应用程序去处理,自己却只提供作为传输层协议的最基本功能。UDP有点类似于用户说什么听什么的机制,但是需要用户充分考虑好上层协议类型并制作相应的应用程序。
TCP充分实现了数据传输时各种控制功能,可以进行丢包的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在UDP中都没有。
此外,TCP作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。TCP通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输。
TCP和UDP是OSI模型中的运输层中的协议。
TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。


11.UDP传输时,数据过大会不会拆包?

我们都知道TCP属于传输层的协议,传输层除了有TCP协议外还有UDP协议。那么UDP是否会发生粘包或拆包的现象呢?答案是不会。UDP是基于报文发送的,从UDP的帧结构可以看出,在UDP首部采用了16bit来指示UDP数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。而TCP是基于字节流的,虽然应用层和TCP传输层之间的数据交互是大小不等的数据块,但是TCP把这些数据块仅仅看成一连串无结构的字节流,没有边界;另外从TCP的帧结构也可以看出,在TCP的首部没有表示数据长度的字段,基于上面两点,在使用TCP传输数据时,才有粘包或者拆包现象发生的可能。

TCP粘包、拆包发生原因

发生TCP粘包或拆包有很多原因,现列出常见的几点,可能不全面,欢迎补充,

1、要发送的数据大于TCP发送缓冲区剩余空间大小,将会发生拆包。

2、待发送数据大于MSS(最大报文长度),TCP在传输前将进行拆包。

3、要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。

4、接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。

等等。

TCP粘包、拆包解决办法

通过以上分析,我们清楚了粘包或拆包发生的原因,那么如何解决这个问题呢?解决问题的关键在于如何给每个数据包添加边界信息,常用的方法有如下几个:

1、发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。

2、发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。

3、可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。

TCP、UDP数据包大小的限制

1、概述

首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层。   
其中以太网(Ethernet)的数据帧在链路层   
IP包在网络层   
TCP或UDP包在传输层   
TCP或UDP中的数据(Data)在应用层   
它们的关系是 数据帧{IP包{TCP或UDP包{Data}}}   

    不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据报(datagram),在链路层叫做帧(frame)。数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理。

在应用程序中我们用到的Data的长度最大是多少,直接取决于底层的限制。   
我们从下到上分析一下:   
1.在链路层,由以太网的物理特性决定了数据帧的长度为(46+18)-(1500+18),其中的18是数据帧的头和尾,也就是说数据帧的内容最大为1500(不包括帧头和帧尾),即MTU(Maximum Transmission Unit)为1500;  
2.在网络层,因为IP包的首部要占用20字节,所以这的MTU为1500-20=1480; 
3.在传输层,对于UDP包的首部要占用8字节,所以这的MTU为1480-8=1472;   
所以,在应用层,你的Data最大长度为1472。当我们的UDP包中的数据多于MTU(1472)时,发送方的IP层需要分片fragmentation进行传输,而在接收方IP层则需要进行数据报重组,由于UDP是不可靠的传输协议,如果分片丢失导致重组失败,将导致UDP数据包被丢弃。   
从上面的分析来看,在普通的局域网环境下,UDP的数据最大为1472字节最好(避免分片重组)。   
但在网络编程中,Internet中的路由器可能有设置成不同的值(小于默认值),Internet上的标准MTU值为576,所以Internet的UDP编程时数据长度最好在576-20-8=548字节以内。
 

2、TCP、UDP数据包最大值的确定     

        UDP和TCP协议利用端口号实现多项应用同时发送和接收数据。数据通过源端口发送出去,通过目标端口接收。有的网络应用只能使用预留或注册的静态端口;而另外一些网络应用则可以使用未被注册的动态端口。因为UDP和TCP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。动态端口的范围是从1024到65535。  

        MTU最大传输单元,这个最大传输单元实际上和链路层协议有着密切的关系,EthernetII帧的结构DMAC+SMAC+Type+Data+CRC由于以太网传输电气方面的限制,每个以太网帧都有最小的大小64Bytes最大不能超过1518Bytes,对于小于或者大于这个限制的以太网帧我们都可以视之为错误的数据帧,一般的以太网转发设备会丢弃这些数据帧。

        由于以太网EthernetII最大的数据帧是1518Bytes这样,刨去以太网帧的帧头(DMAC目的MAC地址48bits=6Bytes+SMAC源MAC地址48bits=6Bytes+Type域2Bytes)14Bytes和帧尾CRC校验部分4Bytes那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes这个值我们就把它称之为MTU。

UDP 包的大小就应该是 1500 - IP头(20) - UDP头(8) = 1472(Bytes)
TCP 包的大小就应该是 1500 - IP头(20) - TCP头(20) = 1460 (Bytes)


12.说说QT创建线程有几种方法,分别说说。

QT新建线程的几种方法:
1.继承Qthread新建一个类,重写run方法,此方法除run之外,其他的都还是在主线程中运行;
2.使用moveToThread将新建线程转移到继承QObject的新类实例中;

方法1:
1.新建一个类WorkThread,基类为QThread。
2.重写类WorkThread的虚函数void run();,即新建一个函数protected void run(),然后对其进行定义。
3.在需要用到多线程的地方,实例WorkThread,然后调用函数WorkThread::start()后,则开启一条线程,自动运行函数run()。
4.当停止线程时,调用WorkThread::wait()函数,等待线程结束,并且回收线程资源。

方法2:

1.新建一个test类,基类为QObject,在此类中写上此线程需要调用的函数作为槽函数;
2.在使用处实例化一个test类;
3.新建一个QThread对象thread,并用connect将信号发送者设置为thread,接收者为实例化的test类;
4.使用test类的moveToThread()方法,参数填入thread;
5.调用thread的start()方法开启线程;
6.在析构函数中退出线程并释放资源。


13.说说c++的3个特性。 

封装,继承,多态。、


14.qt编程中new出来的控件为什么没有delete

   QT的父子对象机制是在 QWidget和QOject中实现的。当我们使用父对象来创建一个对象的时候 ,父对象会把这个对象添加到自己的子对象列表中。当这个父对象被删除的时候,它会遍历它的子对象类表并且删除每一个子对象,然后子对象们自己再删除它们自己的子对象,这样递归调用直到所有对象都被删除。 
       这种父子对象机制会在很大程度上简化我们的内存管理工作,减少内存泄露的风险。我们需要显式删除(就是用Delete删除)的对象是那些使用new创建的并且没有父对象的对象(切记是new的才要delete,通过成员函数获得的对象,没有特殊说明的,千万不要随便delete.)。如果我们在删除一个对象的父对象之前删除它,QT会自动地从它的父对象的子对象列表中移除它的。

      Qt 自动回收不像Java这种,有垃圾回收机制。 Qt 自动回收是靠父子关系。父亲销毁了。他的孩子也销毁。 所以为什么main函数里面main widget/dialog/mainWindow是分配在栈上的原因。其他new出来的东西都以这个widget作为父亲。 当程序最后结束了,main widget弹栈。父类被销毁。子类跟着被销毁。 所以如果你自己new 出来的。没有父类,不删除就会造成内存泄漏。


15.了不了解观察者模式?

一、什么是观察者模式

在许多设计中,经常涉及多个对象都对一个特殊对象中的数据变化感兴趣,而且这多个对象都希望跟踪那个特殊对象中的数据变化,也就是说当对象间存在一对多关系时,在这样的情况下就可以使用观察者模式。当一个对象被修改时,则会自动通知它的依赖对象。

观察者模式是关于多个对象想知道一个对象中数据变化情况的一种成熟的模式。观察者模式中有一个称作“主题”的对象和若干个称作“观察者”的对象,“主题”和“观察者”间是一种一对多的依赖关系,当“主题”的状态发生变化时,所有“观察者”都得到通知。

主要解决:一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

二、观察者模式的结构

1)主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法,比如,添加、删除观察者以及通知观察者更新数据的方法。

(2)观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。

(3)具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题需使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体观察者。

(4)具体观察者(ConcreteObserver):具体观察者是实现观察者接口类的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己的引用添加到具体主题的集合中,使自己成为它的观察者,或让这个具体主题将自己从具体主题的集合中删除,使自己不再是它的观察者。

三、观察者模式的使用场景

1)当一个对象的数据更新时需要通知其他对象,但这个对象又不希望和被通知的那些对象形成紧耦合。

(2)当一个对象的数据更新时,这个对象需要让其他对象也各自更新自己的数据,但这个对象不知道具体有多少对象需要更新数据。

观察者模式在实际项目的应用中非常常见,比如你到 ATM 机器上取钱,多次输错密码,卡就会被 ATM吞掉,吞卡动作发生的时候,会触发哪些事件呢?第一摄像头连续快拍,第二,通知监控系统,吞卡发生;第三,初始化 ATM 机屏幕,返回最初状态,你不能因为就吞了一张卡,整个 ATM 都不能用了吧,一般前两个动作都是通过观察者模式来完成的。观察者可以实现消息的广播,一个消息可以触发多个事件,这是观察者模式非常重要的功能。

使用观察者模式也有两个重点问题要解决: 

广播链的问题

如果你做过数据库的触发器,你就应该知道有一个触发器链的问题,比如表 A 上写了一个触发器,内容是一个字段更新后更新表 B 的一条数据,而表 B 上也有个触发器,要更新表 C,表 C 也有触发器…,完蛋了,这个数据库基本上就毁掉了!我们的观察者模式也是一样的问题,一个观察者可以有双重身份,即使观察者,也是被观察者,这没什么问题呀,但是链一旦建立,这个逻辑就比较复杂,可维护性非常差,根据经验建议,在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次),这还是比较好控制的;


异步处理问题

被观察者发生动作了,观察者要做出回应,如果观察者比较多,而且处理时间比较长怎么办?那就用异步呗,异步处理就要考虑线程安全和队列的问题,这个大家有时间看看 Message Queue,就会有更深的了解。

四、观察者模式的优缺点

优点:

  1、具体主题和具体观察者是松耦合关系。由于主题接口仅仅依赖于观察者接口,因此具体主题只是知道它的观察者是实现观察者接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题接口,因此具体观察者只是知道它依赖的主题是实现主题接口的某个类的实例,但不需要知道具体是哪个类。

  2、观察者模式满足“开-闭原则”。主题接口仅仅依赖于观察者接口,这样,就可以让创建具体主题的类也仅仅是依赖于观察者接口,因此,如果增加新的实现观察者接口的类,不必修改创建具体主题的类的代码。。同样,创建具体观察者的类仅仅依赖于主题接口,如果增加新的实现主题接口的类,也不必修改创建具体观察者类的代码。

缺点: 

  1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

  2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。

  3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化


16.qt/vs中,怎样调试?

一个链接 

QT+VS配置及调试_HelloEarth_的博客-CSDN博客_vs+qt配置


17.多线程共享一个全局数据时需要注意哪些问题?

解决多线程共享全局变量问题,在多线程中实现多任务难免会遇见共享全局变量问题,当多个线程同时对一个全局变量操作,会出现资源竞争问题,从而导致数据结不正确,即遇到线性安全问题
那么该如何解决呢?
引入同步机制

同步机制:
        1.为什么会有这个机制,有什么作用?
            同步:跟字面的意思不太一样,它是指协同步调,按预定的先后顺序进行运行,比如:你说完,我再说;你做完,我再做;你执行完,我再执行。
                同步就是等待,等你做完我在做,在多线程编程中,一些敏感的数据不允许被多个线程同时访问,因为会出现线程安全问题,通过线程同步机制
                能够保证共享数据在任何时候,最多有一个线程访问,以保证数据的正确性!
        具体以什么方式解决?
        引入互斥锁(下点) 


互斥锁解决共享全局变量出现的线程安全问题
        1.互斥锁是实现同步机制的一种解决方案,好比多线程是实现多任务的一种方法
        2.某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,
          将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,
          从而保证了多线程情况下数据的正确性。
        3.具体的操作
            1.取得锁:mutex_lock = threading.Lock()
            2.上锁:mutex_lock.acquire()
            3.释放锁:mutex_lock.release()
        4.注意点:
            在共享全局变量中,当用互斥锁锁上时,当运算的数目比较大时,产生的结果可能有些误差,但最终结果大体相同  
 


18.如何自定义一个按钮

1.创建一个类让其继承QWidget,点击下一步下一步最后完成

2.打开MyPushButton,让其继承QPushButton。

3.重载其构造函数,让其传入按钮背景图片的路径。可设按钮的固定尺寸大小、icon、样式等。设置完成后这个自定义按钮就完成了

4.新建一个window类进行测试,在测试类的构造方法中加入如下的代码,并使用信号和槽函数监听按钮的点击事件

一个链接

QT 语言学习 day07 ui 界面 三种样式的按钮开关的制作!__She001的博客-CSDN博客_qt按钮开关


19.熟不熟悉数据库

一个链接

QT 语言的学习 day10 数据库的学习 增删改 (QT 自带的数据库 QSqlDatabase数据库)__She001的博客-CSDN博客


20.如何通过网络上传一个文件

两个链接

本地文件如何上传到网上_webxiaoma的博客-CSDN博客_怎样上传文件到网上

电脑端文件上传如何上传网络文件-百度经验 (baidu.com)


21.dds了不了解

DDS采用的通信模型是一种多对多单向数据交换,其中产生数据的应用程序将数据发布到属于使用数据的应用程序的订阅者的本地缓存。信息流由负责数据交换的实体之间建立的服务质量(QoS)策略来控制。

作为一个以数据为中心的模型,DDS建立在所有感兴趣的应用程序都可以访问的“全局数据空间”的概念之上。提供信息的应用程序作为发布者,访问部分数据空间的应用程序作为订阅者。每当发布者向该空间发布新数据时,中间件就将该信息传播给所有感兴趣的订阅者。

通信发生在多个域之间,即连接所有能够相互通信的分布式应用程序的孤立抽象平面。只有属于同一个域的实体才能进行交互,订阅数据的实体和发布数据的实体之间的匹配通过主题进行中介。主题是明确的标识符,它将在域中惟一的名称与数据类型和一组附加的特定于数据的QoS相关联。

DDS实体被建模为类或类型化接口,后者意味着更有效的资源处理,因为在执行前了解数据类型允许提前分配内存,而不是动态分配。


22.QT 信号槽机制

信号与槽(Signal & Slot)是 Qt 编程的基础,也是 Qt 的一大创新。因为有了信号与槽的编程机制,在 Qt 中处理界面各个组件的交互操作时变得更加直观和简单。

信号(Signal)就是在特定情况下被发射的事件,例如PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的 CurrentIndexChanged() 信号。

GUI 程序设计的主要内容就是对界面上各组件的信号的响应,只需要知道什么情况下发射哪些信号,合理地去响应和处理这些信号就可以了。

槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

信号与槽关联是用 QObject::connect() 函数实现的,其基本格式是:

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

connect() 是 QObject 类的一个静态函数,而 QObject 是所有 Qt 类的基类,在实际调用时可以忽略前面的限定符,所以可以直接写为:

connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

其中,sender 是发射信号的对象的名称,signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。

SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。例如,在 samp2_1(前面章节中的项目)的 ui_widget.h 文件中,在 setupUi() 函数中有如下的语句:

QObject::connect(btnClose, SIGNAL(clicked()), Widget, SLOT(close()));

其作用就是将 btnClose 按钮的 clicked() 信号与窗体(Widget)的槽函数 close() 相关联,这样,当单击 btnClose 按钮(就是界面上的“Close”按钮)时,就会执行 Widget 的 close() 槽函数。

关于信号与槽的使用,有以下一些规则需要注意:

  • 一个信号可以连接多个槽,例如:

    connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int));
    connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int));

    这是当一个对象 spinNum 的数值发生变化时,所在窗体有两个槽进行响应,一个 addFun()用于计算,一个 updateStatus() 用于更新状态。

    当一个信号与多个槽函数关联时,槽函数按照建立连接时的顺序依次执行。

    当信号和槽函数带有参数时,在 connect()函数里,要写明参数的类型,但可以不写参数名称。
  • 多个信号可以连接同一个槽,例如在 samp2_2(前面章节中的项目)中,让三个选择颜色的 RadioButton的clicked() 信号关联到相同的一个自定义槽函数 setTextFontColor()。

    connect(ui->rBtnBlue,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
    connect(ui->rBtnRed,SIGNAL(clicked()),this,SLOT(setTextFontColor()));
    connect(ui->rBtnBlack,SIGNAL(clicked()),this,SLOT(setTextFontColor()));

    这样,当任何一个 RadioButton 被单击时,都会执行 setTextFontColor() 函数。
  • 一个信号可以连接另外一个信号,例如:

    connect(spinNum, SIGNAL(valueChanged(int)), this, SIGNAL (refreshInfo(int));

    这样,当一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。
  • 严格的情况下,信号与槽的参数个数和类型需要一致,至少信号的参数不能少于槽的参数。如果不匹配,会出现编译错误或运行错误。
  • 在使用信号与槽的类中,必须在类的定义中加入宏 Q_OBJECT。
  • 当一个信号被发射时,与其关联的槽函数通常被立即执行,就像正常调用一个函数一样。只有当信号关联的所有槽函数执行完毕后,才会执行发射信号处后面的代码。


23.QT 如何从一个UI进入另一个UI,

父界面隐藏,子界面显示


24.oracle的rman命令或以及是用的什么版本的数据库管理工具,

两个链接

Oracle中RMAN基本命令教程_WoLykos的博客-CSDN博客

oracle RMAN 简要介绍及使用_conghe5517的博客-CSDN博客


25.部署项目Linux用的哪些命令

1.命令 : 建造文件夹  mkdir 

2.一开始常用的命令是cd:

cd是用于切换文件路径的,其中…/可以切换到上当前路径的上一个路径

3.开启tomcat服务器命令(首先需要切换到tomcat的bin目录下):

一般使用的是  ./startup.sh  或者 bash startup.sh

4.关闭tomcat服务器命令(路径同上):

 一般使用的是  ./shutdown.sh  或者 bash shutdown.sh

5.查看tomcat日志(需要切换到tomcat的logs目录下)

 执行命令  tailf catalina.out   或者  tail -f catalina.out  
1
6.查看tomcat是否开启(切换到tomcat的bin目录下)

 执行 ps ef |  grep java

7.杀死tomcat进程

 执行 kiil -9 5263(5263就是上面的红框框住的)

8.查看端口占用情况

 执行命令  netstat -tunlp |grep 端口号   
 

9.mysql基本命令

连接数据库执行命令: mysql -u 用户名 -p

重启mysql服务执行命令: service mysql restart

开启mysql服务执行命令: service mysql start

停止mysql服务执行命令: service mysql stop

查看mysql状态执行命令: >>mysql


26.c++和qt的单例模式 调试 创建多线程  抽象类

什么是单例
单例是一种软件设计模式,采用单例模式书写的类可以确保在一个工程中只有一个对象实例。再通俗点,就是一个类写好了之后,就不需要也无法再把这个类实例化了,因为写这个类的时候已经确保了有且仅有一个已经实例化的对象。
这样不是很蠢么?花了这么多功夫写了一个类,你告诉我这个类没法用来new出对象了?那我怎么使用这个类?我写个配合静态变量的静态函数,使用起来不是更方便?
当然不蠢,非但不蠢,而且单例模式是所有设计模式中使用最为频繁的一个设计模式。没法new出对象,因为单例模式已经帮你new了一个对象,而且让你的工程中只有这个对象了;使用这个对象只需要包含头文件,然后调用接口指针函数就可以了;静态的全局函数或变量代码实现起来方便,但是不具有类的封装性和灵活性。
 

如何让类无法实例化
首先要清楚类实例化无非就是三种方式:
1)采用构造函数实例化;
2)用拷贝函数实现实例化;
3)赋值操作实现实例化。
所以,只需要把这个类的构造函数、拷贝函数、赋值操作写成私有的,就无法调用这些函数,自然就无法实例化了。
正如上文所示的几个函数:

private:
Makelog(){} //构造函数
Makelog(const Makelog&){} //拷贝函数
Makelog& operator ==(const Makelog&){} //赋值操作符重写
 

详细的知识 (一个链接)

qt的单例模式

Qt下实现支持多线程的单例模式_lusanshui的博客-CSDN博客_qt 单例模式 多线程

c++ 抽象类

C++ 抽象类 - balingybj - 博客园 (cnblogs.com)


27.静态函数

在类中,static 除了可以声明静态成员变量,还可以声明静态成员函数。普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员。

编译器在编译一个普通成员函数时,会隐式地增加一个形参 this,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象后通过对象来调用,因为它需要当前对象的地址。而静态成员函数可以通过类来直接调用,编译器不会为它增加形参 this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。

普通成员变量占用对象的内存,静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,也就是说静态成员函数不能访问普通成员变量,只能访问静态成员变量。

普通成员函数必须通过对象才能调用,而静态成员函数没有 this 指针,无法在函数体内部访问某个对象,所以不能调用普通成员函数,只能调用静态成员函数。

静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。


 


28.数据库一般是mysql或oracle

一、宏观上的区别
1、mysql与oracle都是关系型数据库,应用于各种平台。mysql最开始是一个瑞典公司开发的,但后来被sun公司收购,后来sun又被oracle收购,所以现在可以说mysql属于甲骨文公司了,mysql开源免费的,而oracle则是收费的,并且价格非常高。mysql属于轻量型数据库;oracle属于重量型数据库。

2、mysql默认端口:3306,默认用户:root;oracle默认端口:1521,默认用户:system
mysql的安装卸载很简单,oracle相对来说会麻烦一点,安装所用的空间差别也是很大的,mysql安装后差不多一两百兆,而oracle则有3G左右,且使用的时候oracle占用特别大的内存空间和其他机器性能。

3、mysql登录:mysql -hlocalhost -uroot -p密码(h:host、u:user、p:password)
oracle登录:sqlplus user_name/password@IP:port/instance_name;(其中可以把IP地址,端口号,实例名写在一个TNS文件中取一个别名,登陆的时候输入这个别名就行了)
初学阶段,图形化工具,mysql可以使用Navicat,Oracle一般用PLSQL,也可以用sqlyog等;

4、mysql的管理工具较少,在Linux下的管理工具的安装有时需要安装额外的包(phpmyadmin,etc),有一定复杂性。
oracle有多重成熟命令行、图形界面、web管理工具,还有很多第三方的管理工具,管理极其方便高效。
oracle支持大并发,大访问量,是OLTP最好的工具。

5、mysql:默认用户是root,用户下可以创建好多数据库,每个数据库下还有好多表,一般情况下都是使用默认用户,不会创建多个用户;
oracle:创建一个数据库,数据库下有好多用户:sys、system、scott等,不同用户下有好多表,一般情况下只创建一个数据库用。

二、操作区别
1、数据库中表字段类型:
mysql:int、float、double等数值型,varchar、char字符型,date、datetime、time、year、timestamp等日期型。
oracle:number(数值型),varchar2、varchar、char(字符型),date(日期型)等…
其中char(2)这样定义,这个单位在oracle中2代表两个字节,mysql中代表两个字符。
其中varchar在mysql中,必须给长度例如varchar(10)不然插入的时候出错。

2、主键:
mysql一般使用自动增长类型,在创建表时只要指定表的主键auto increment,插入记录时,不需要再指定该记录的主键值,mysql将自动增长。
oracle没有自动增长类型,主键一般使用的序列,插入记录时将序列号的下一个值赋给该字段即可,只是ORM框架是只要是native主键生成策略即可。

3、单引号处理:mysql里可以用双引号包起字符串,oracle只可以用单引号包起字符串。

4、分页处理:
mysql是直接在SQL语句中使用limit就可以实现分页
oracle则是需要用到伪劣ROWNUM和嵌套查询

5、对事务提交:
mysql默认是自动提交,可以修改为手动提交
oracle默认不自动提交,需要手动提交,需要在写commit指令或点击commit按钮。

6、对事务的支持:mysql在innodb存储引擎的夯机所的情况下才支持事务,而oracle则完全支持事务。

7、事务隔离级别:
mysql是repeatable read的隔离级别,而oracle是read commited的隔离级别;
同时二者都支持serializable串行化事务隔离级别,可以实现最高级别的读一致性。每个session提交后其它session才能看到提交的更改;
oracle通过在undo表空间中构造多版本数据块来实现读一致性,每个session查询时,如果对应的数据块发生变化,oracle会在undo空间中为这个session构造它查询时的旧的数据块;
mysql没有类似oracle的构造多版本数据的机制,只支持read commited的隔离级别,一个session读取数据时,其他session不能更改数据,但可以在表最后插入数据;session更新数据时,要加上排它锁,其他session无法访问数据。

8、并发性:
mysql以表级锁为主,对资源锁定的粒度很大,如果一个session对一个表加锁时间过长,会让其他session无法更新此表中的数据。虽然Innodb引擎表可以用行级锁,但这个行级锁的机制依赖于表的索引,如果表没有索引,或者sql语句没有使用索引,那么仍然使用表级锁;
oracle使用行级锁,对资源锁定的粒度要小很多,只是锁定sql需要的资源,并且加锁是在数据库中的数据行上,不依赖于索引,所以oracle对并发性的支持要好很多。

9、逻辑备份:
mysql逻辑备份时要锁定数据,才能保证备份的数据是一致的,影响业务正常的dml使用,oracle逻辑备份时不锁定数据,且备份的数据是一致的。

10、复制:
mysql:复制服务器配置很简单,但主库出问题时,从库可能丢失一定的数据,且需要手工切换从库到主库;
oracle:既有堆或拉式的传统数据复制,也有dataguard的双机或多机容灾机制,主库出问题时,可以自动切换备库到主库,但配置管理较复杂。

11、性能诊断:
mysql的诊断调优方法较少,主要有慢查询日志;
oracle有各种成熟的性能诊断调优工具,能实现很多自动分析、诊断功能。比如awr、addm、sqltrace、tkproof等。

12、保存数据的持久性:
mysql默认提交sql语句,但如果更新过程中出现db或主机重启的问题,也许会丢失数据;
oracle把提交的sql操作先写入了在线联机日志文件中,保持到了硬盘上,可以随时恢复。

13、热备份:
oracle有成熟的热备份工具rman,不影响用户使用数据库。即使备份的数据库不一致,也可以在恢复时通过归档日志和联机重做日志进行一致的回复。
mysql:
myisam引擎:用mysql自带的mysqlhostcopy热备时,需要给表加读锁,影响dml操作;
innodb引擎:它会备份innodb的表和索引,但是不会备份.frm文件,用ibbackup备份时,会有一个日志文件记录备份期间的数据变化,因此可以不用锁表,不影响其它用户使用数据库,但此工具是收费的。
innobackup是结合ibbackup使用的一个脚本,它会协助对.frm文件的备份。

14、日期转换:
mysql中日期转换用dateformat()函数;
oracle用to_date()与to_char()两个函数。
 

两个链接

MySQL数据库基本操作

MySQL数据库和Oracle数据库的区别_农名工的博客-CSDN博客

Oracle数据库基本操作

Oracle数据库基本操作_sensh 的博客-CSDN博客


29.qt 通讯: 用过哪些。

TCP  

UDP


30.udp有做过协议解析吗?      udp中int类型怎么解析的

三个链接 

UDP 协议解析_ITKaven的博客-CSDN博客

UDP协议的详细解析_李大坝超欧的的博客-CSDN博客_udp

UDP协议解析_‍oOoOoOooOO的博客-CSDN博客_udp协议号

udp中int类型怎么解析的

在使用linux服务器接收数据包时,接受的是一个byte类型的数组。所以当我们对这个数组进行解析时,会根据不同字段的大小来选择合适的类型去进行转换。

比如8位的字段就应该转为byte类型。

比如16位的字段就应该转为short类型。

比如32位的字段就应该转为int类型。

比如64位的字段就应该转为long类型。


31.qt 处理大小端怎么处理

两个链接

【QT】Qt对大小端字节序的处理_会飞的代码UP的博客-CSDN博客_qt大小端转换

大端模式、小端模式及其在Qt中的转换_usownh的博客-CSDN博客_qt字节序转换


32.了解哪些设计模式。会用哪些设计模式

  • 设计模式是对设计原则的具体化。用江湖话说就是武林秘籍,总结出来的一些固定套路,可以帮助有根基的程序员迅速打通任督二脉,从此做什么都特别快。常用的模式及其场景如下。

    1) 单例模式。

    单例模式是一种常用的软件设计模式。

    在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。

    应用场景:如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

    2) 工厂模式。

    工厂模式主要是为创建对象提供了接口。

    应用场景如下:

    a、 在编码时不能预见需要创建哪种类的实例。

    b、 系统不应依赖于产品类实例如何被创建、组合和表达的细节。

    3) 策略模式。

    策略模式:定义了算法族,分别封装起来,让它们之间可以互相替换。此模式让算法的变化独立于使用算法的客户。

    应用场景如下。

    a、 一件事情,有很多方案可以实现。

    b、我可以在任何时候,决定采用哪一种实现。

    c.、未来可能增加更多的方案。

    d、 策略模式让方案的变化不会影响到使用方案的客户。

    举例业务场景如下。

    系统的操作都要有日志记录,通常会把日志记录在数据库里面,方便后续的管理,但是在记录日志到数据库的时候,可能会发生错误,比如暂时连不上数据库了,那就先记录在文件里面。日志写到数据库与文件中是两种算法,但调用方不关心,只负责写就是。

    4) 观察者模式。

    观察者模式又被称作发布/订阅模式,定义了对象间一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

    应用场景如下:

    a、对一个对象状态的更新,需要其他对象同步更新,而且其他对象的数量动态可变。

    b、对象仅需要将自己的更新通知给其他对象而不需要知道其他对象的细节。

    5) 迭代器模式。

    迭代器模式提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。

    应用场景如下:

    当你需要访问一个聚集对象,而且不管这些对象是什么都需要遍 历的时候,就应该考虑用迭代器模式。其实stl容器就是很好的迭代器模式的例子。

    6) 模板方法模式。

    模板方法模式定义一个操作中的算法的骨架,将一些步骤延迟到子类中,模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。

    应用场景如下:

    对于一些功能,在不同的对象身上展示不同的作用,但是功能的框架是一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值