2023届C/C++软件开发工程师校招面试常问知识点复盘Part 3

目录

          • 21、QT的信号槽机制
          • 22、野指针与悬空指针
          • 23、MFC中的`SendMessage()`与`PostMessage()`的区别
          • 24、Float是怎么存储小数的?
          • 25、New与malloc
          • 26、Switch与if else的区别
          • 27、怎么实现在main()函数之前运行函数
          • 28、STL中容器了解哪些
          • 29、Map底层是什么 —— 红黑树
          • 30、红黑树原理是什么

21、QT的信号槽机制

信号的本质:

信号通常是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号

信号的本质是事件, 但是是以函数的形式存在,在Qt中信号相对应的函数,只有声明没有定义

信号的呈现形式是一个函数,也就是说某个事件产生了,Qt框架就会调用某个对应的信号函数,通知使用者

  • Qt中信号的发出者是某个实例化的类对象,对象内部可以进行相关事件的检测.

槽的本质:

槽函数是Qt中一类可以对Qt框架中产生的信号进行处理的函数,另外槽函数也可以做为类的普通成员函数来使用

  • Qt中槽函数的所有者也是某个类的实例对象

信号和槽之间的关系:

通常在不做任何处理时,Qt中的信号和槽是独立的,没有关系;

因为某种需要我们需要将他们连接在一起: 这时候用到的就是QObject类中的connect函数,将信号与槽连接在一起

QMetaObject::Connection QObject::connect(
    	const QObject *sender, PointerToMemberFunction signal, 
        const QObject *receiver, PointerToMemberFunction method, 
		Qt::ConnectionType type = Qt::AutoConnection);
参数:
  - sender:   	发出信号的对象
  - signal:   	属于sender对象, 信号是一个函数, 这个参数的类型是函数指针, 信号函数地址
  - receiver: 	信号接收者
  - method:   	属于receiver对象, 当检测到sender发出了signal信号, receiver对象调用method方法,信号发出之后的处理动作
  - type:		连接方式
 
//  参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal, 
        const QObject *receiver, &QObject::method);

关于connect()函数的第5个参数:ConnectionType

首先ConnetionType具有默认参数:AutoConnection,第五个参数主要是解决多线程情况下信号与槽之间的配合关系的,指定槽函数在那个线程中执行

AutoConnection自动连接。如果信号与槽(信号的发送者和接收者)位于同一个线程,等同于直接连接;如果信号与槽位于不同的线程中,等同于队列连接

DirectConnection直接连接。当信号被发射后,槽函数立即执行处理,无论槽函数的所有者属于哪个线程;槽函数都将在信号发送者所在的线程执行

QueuedConnection队列连接。信号被放入接收者所在线程的信号队列中,等待线程取到该信号后再执行槽函数,也即槽函数执行在接收者对象所在的线程

BlockingQueuedConnection阻塞队列连接。槽函数的调用时机同队列连接;不同的是该模式下,信号发送者所在的线程会阻塞,一直等到该信号被槽函数处理并返回才解除阻塞(有点类似MFC中的SendMessage()

UniqueConnection单一连接。该参数可以与其余的四个参数一起使用,用于避免重复连接

槽函数的本质是一个回调函数,在某个信号产生之后,由Qt框架来执行调用工作

也即信号和槽本质上都是函数,当发生了某个事件之后,这个事件关联的对象会根据事件的类型发出信号

因为我们已经使用connnect函数将信号和槽函数关联起来,因此Qt框架会帮我根据信号调用信号接收者对应的槽函数,这类似一个回调函数的形式

自定义信号:

  1. 信号是类的成员函数
  2. 返回值是void类型
  3. 名字随意
  4. 参数随意,但是信号的参数要大于等于对应的槽函数的参数
  5. 信号只需要声明,不需要实现
  6. signals关键字指定
  7. 发射信号的本质就是调用一下信号函数

自定义槽函数:

  1. 返回值void类型
  2. 还可以做为普通函数正常使用
  3. 支持重载
  4. 槽函数的参数数量要根据信号的参数指定:信号负责传递数据,槽函数负责接收数据
  5. 槽函数可以是类成员函数,全局函数,静态函数,Lambda表达式

22、野指针与悬空指针

野指针:野孩子野人,从来没有被教育过,也即指针没有被初始化

悬空指针:孤儿,有过爸爸妈妈,但是都去世了,是孤儿,也即指针指向的内存被释放了,但是没有及时地置空

23、MFC中的SendMessage()PostMessage()的区别
LRESULT SendMessage(
  [in] HWND   hWnd,
  [in] UINT   Msg,
  [in] WPARAM wParam,
  [in] LPARAM lParam
);

SendMessage(阻塞的)函数用于给一个窗口或几个窗口发送一个指定的消息,并调用窗口处理程序处理该消息,直到该消息被处理之后函数才会返回

BOOL PostMessageA(
  [in, optional] HWND   hWnd,
  [in]           UINT   Msg,
  [in]           WPARAM wParam,
  [in]           LPARAM lParam
);

PostMessage(非阻塞的)函数是用于把一个消息放进指定窗口的工作线程所关联的消息队列中,然后立即返回,不等待线程去处理该消息

24、Float是怎么存储小数的?

是使用IEEE 754浮点表示法

对于一个float,是4字节32位,从高位到低位依次是符号阶码尾数(1 ,8,23)

符号位决定了这个数的正负

阶码是权重

尾数是一个二进制小数

double是64位(1,11,52)

25、New与malloc
26、Switch与if else的区别

①switch…case…只能用于case值为常量的分支结构,而if…else…更加灵活。

②if判断条件为逻辑表达式,可以是布尔类型的合法表达式、可以是常量、枚举等。而switch 通常处理算术表达式,或字符。

③switch 进行一次条件判断后直接执行到程序的条件语句。而if…else 有几种条件,就得判断多少次

④相比if语句,switch语句是以空间换时间的分支结构。因为它要生成跳转表,所以占用较多的代码空间。当case常量分布范围很大但实际有效值又比较少的情况,switch…case的空间利用率将变得很低。

⑤分支较多时,使用switch的效率高于if,除非第一个if条件就为真

switch (expression)
{
case /* constant-expression */:
  /* code */
  break;

default:
  break;
}
27、怎么实现在main()函数之前运行函数

全局对象一般在main()函数之前初始化,因此可以在全局对象的构造函数中调用某些函数

main函数的参数argc、argv会在main执行之前进行传递

②类的静态成员变量一般在main()函数执行前就初始化

28、STL中容器了解哪些

2023届C/C++软件开发工程师校招面试常问知识点复盘Part 3_第1张图片

容器适配器:

queue、stack

29、Map底层是什么 —— 红黑树
30、红黑树原理是什么

红黑树

红黑树定义:用红色和黑色标记的自平衡二叉搜索树, 所谓平衡指的不是完全平衡,而是大致平衡

查询、插入、删除的时间复杂度O(logn)

红黑树的性质:

  1. 首先是一个二叉搜索树(又称为有序二叉树,定义如下)
    • 若任意节点的左子树不为空,则左子树上所有节点的值均小于他的根节点的值
    • 若任意节点的右子树不为空,则右子树上所有节点的值均大于他的根节点的值
    • 任意节点的左右子树也分别为二叉搜索树
  2. rootNil节点是黑色
  3. 不存在两个相邻的红色节点,相邻指的是父子相邻的关系
  4. 任意节点到其每个叶子节点的所有简单路径上都有相同数目的黑色节点

你可能感兴趣的:(校招,C++学习笔记,c语言,c++,面试)