9.2日汇川一面
Q1:
QT的信号和槽机制实现
信号槽通过什么函数来绑定,了解QT的connect函数?
1.信号与槽(Signal and Slot)
基础概念:
信号和槽是用于对象之间的通信,它是Qt的核心机制。信号和槽其实是观察者模式的一种实现。
举个例子,在一个十字路口,信号灯变成了绿色,对面的汽车看到后就启动了。信号灯就是发送信号的对象,绿灯亮是它发送的信号 (signal),汽车是接收对象,汽车行驶是汽车对信号的响应,也叫槽 (slot)。
再举一个例子,比如在一个主窗口内有一个关闭按钮,如果点击这个按钮窗口就会关闭,那么关闭按钮是发送信号的对象,它发送的信号是点击,接收信号的对象是窗口,响应信号的槽是关闭窗口。
创建信号和槽:
只有QObject及其派生类才能使用信号和槽机制,且在类之中还需要使用Q_OBJECT宏
1、信号需符合以下规则
- 信号使用signals关键字声明,在其后面有一个冒号“:”,==
signal:void s();
==在其前面不能有public、private、protected访问控制符,信号默认是public的。 - 信号只需像函数那样声明即可,其中可以有参数,参数的主要作用是用于和槽的通信,这就像普通函数的参数传递规则一样。信号虽然像函数,但是对他的调用方式不一样,信号需要使用emit关键字发送(QT5之后不再使用)。
- 信号只需声明,不能对其进行定义,信号是由moc自动生成的。
- 信号的返回值只能是void类型的。
2、声明槽需符合以下规则
- 声明槽需要使用slots关键字,在其后面有一个冒号“:”,
slot: 函数定义
,且槽需使用public、private、protected访问控制符之一。 - 槽就是一个普通的函数,可以像使用普通函数一样进行使用,槽与普通函数的主要区别是,槽可以与信号关联。
3、发射信号需符合以下规则:
- 发射信号需要使用emit关键字,注意,在emit后面不需要冒号。
- emit发射的信号使用的语法与调用普通函数相同,比如有一个信号为void f(int),则发送的语法为:emit f(3);
- 当信号被发射时,与其相关联的槽函数会被调用(注意:信号和槽需要使用QObject::connect函数进行关联之后,发射信号后才会调用相关联的槽函数)。
- 注意:因为信号位于类之中,因此发射信号的位置需要位于该类的成员函数中或该类能见到信号的标识符的位置。
2.信号与槽通过connect函数来绑定
信号和槽使用QObject类中的成员函数connect进行关联,函数有多个重载版本。
connect(发送对象,信号,接收对象,槽函数);
其中信号的指定需要SIGNAL()
宏,槽函数用SLOT()
宏,这两个宏能将括号的内容转换为与形参对应的 const char*
形式。
Q2:
如何理解多态
(答同一对象对于不同信息的不同处理方式,错误的,然后答了编译时多态和运行时多态)
通过父类指针找到子类对象的寻址方式
(答虚函数表)
虚函数表是父类和子类共有的,还是单独的
(答共有的)
1.如何理解多态
向不同对象发送同一消息,不同的对象在接收时会产生不同的行为
多态分为编译时多态和运行时多态,前者实现方式是重载,后者实现方式是重写。
2.通过父类指针找到子类对象的寻址方式
通过基类指针访问派生类对象的方法是虚函数和动态绑定
虚函数:你可以在基类中声明一个虚函数,然后在派生类中重写(override)这个虚函数
动态绑定:通过使用基类指针指向派生类对象,并在运行时确定对象的类型,可以实现动态绑定。**C++使用虚函数表(vtable)**来实现这一机制。虚函数表是一种存储了指向虚函数地址的数组。
3.虚函数表是父类和子类共有的嘛?
不是,父类和子类分别保存一个虚函数表
子类继承父类的时候,会复制父类的虚函数表,两者用独立的指针如果子类没有重写虚函数,子类的虚函数表与父类的一致,但这并不是说明父类和子类共用,因为父类和子类存储该表的地址是不同的(表里的内容一致),如果子类重写了虚函数,子类的虚函数表将保存新函数的地址。
Q3:
TCP三次握手
(答流程还行,但是有些概念没表述清楚SYN,Ack,Seq)
- 一开始,客户端和服务端都处于
CLOSE
状态。先是服务端主动监听某个端口,处于LISTEN
状态 - 客户端会随机初始化序号(
client_isn
),将此序号置于 TCP 首部的「序号」字段中,同时把SYN
标志位置为1
,表示SYN
报文。接着把第一个 SYN 报文发送给服务端,表示向服务端发起连接,该报文不包含应用层数据,之后客户端处于SYN-SENT
状态。 - 服务端收到客户端的
SYN
报文后,首先服务端也随机初始化自己的序号(server_isn
),将此序号填入 TCP 首部的「序号」字段中,其次把 TCP 首部的「确认应答号」字段填入client_isn + 1
, 接着把SYN
和ACK
标志位置为1
。最后把该报文发给客户端,该报文也不包含应用层数据,之后服务端处于SYN-RCVD
状态。1次握手 - 客户端收到服务端报文后,还要向服务端回应最后一个应答报文,首先该应答报文 TCP 首部
ACK
标志位置为1
,其次「确认应答号」字段填入server_isn + 1
,最后把报文发送给服务端,这次报文可以携带客户到服务端的数据,之后客户端处于ESTABLISHED
状态。2次握手 - 服务端收到客户端的应答报文后,也进入
ESTABLISHED
状态。3次握手
Q4:
在调试程序时有没有遇到一些内存相关的问题
(答在做加密的项目的时候出现过一些内存泄漏的情况,通过梳理并规范malloc和free的使用之后,解决了这些问题)
如何定位C++内存泄漏
(答不会)
1.C++如何定位内存泄漏
-
日志:这种方案的核心思想,就是在每次分配内存的时候,打印指针地址,在释放内存的时候,打印内存地址,这样在程序结束的时候,通过分配和释放的差,如果分配的条数大于释放的条数,那么基本就能确定程序存在内存泄漏,然后根据日志进行详细分析和定位。
-
统计:统计方案可以理解为日志方案的一种特殊实现,其主要原理是在分配的时候,统计分配次数,在释放的时候,则是统计释放的次数,这样在程序结束前判断这俩值是否一致,就能判断出是否存在内存泄漏。
-
内存泄漏检测工具: C++(valgrind) JAVA(MAT)
Q5:
接触过数据库了嘛?
(我是SB,说接触的不多,就没让他问)
Q6:
毕业时间,自我评价
反问:
主要业务
工厂自动化,现场的监控
面试需要几轮,这个流程是什么样的
3轮,技术初面,总监面,HR面
大概多久出面试结果
待定,等待排序结果