二阶段项目评审所有提问整理

1、在Qt中我们用到信号和槽的机制实现监听响应,那如果在c++/c中改如何实现

回答:回调函数

(1)首先我们要明确函数可以作为函数的参数来传递
(2)首先至少要有 3 种类型的函数
主函数 :相当于整个程序的引擎,调度各个函数按序执行
回调函数 :一个独立的功能函数,如写文件函数
中间函数 :一个介于主函数和回调函数之间的函数,登记回调函数,通知主函数,起到一个桥梁的作用
(3)例子

```cpp
 void basketball()//回调函数
 {
     printf("选择篮球");
 }
 void football()//回调函数
 {
     printf("选择足球");
  }
void selectball(void (* ball)(int))//中间函数
{
    printf("选择什么球?");
    ball();
}
int main(void)//主函数
{
    selectball(basketball);
    selectball(football);
    return 0;
}

(4)回调函数的执行流程
a、主函数需要调用回调函数

b、中间函数登记回调函数

c、触发回调函数事件

d、调用回调函数

e、响应回调事件

(5)最后一个例子
你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。

在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做 触发回调事件,店员给你打电话叫做 调用回调函数,你到店里去取货叫做 响应回调事件
(6) 为什么Qt使用信号与槽机制而不是传统的回调函数机制进行对象间的通信呢?
① 回调函数的本质是“你想让别人的代码执行你的代码,而别人的代码你又不能动”这种需求下产生的。(所以把回调函数作为参数传递)
②Qt使用信号与槽机制来解决这个问题,程序员只需要指定一个类含有哪些信号函数、哪些槽函数,Qt会处理信号函数和槽函数之间的绑定。当信号函数被调用时,Qt会找到并执行与其绑定的槽函数。允许一个信号函数和多个槽函数绑定,Qt会依次找到并执行与一个信号函数绑定的所有槽函数,这种处理方式更灵活。

2、C与C++ struct与类的区别

(1)结构体不具备类的继承多态特性
(2)结构体只是不同类别数据的一种包装,而类同时具备属性和方法,同时类的使用在需要比较有层次的数据上 面
(3)结构体没有默认的构造函数,但是可以自己添加,同时结构体没有析构函数
(4)
(5) 关于默认访问权限:class中默认的成员访问权限是private的,而struct中则是public的
(6)关于继承方式:class继承默认是private继承,而struct默认是public继承
(7)结构体没有 不能有protected 修饰符
(8)结构体可以不使用new 初始化, 但是类必须要

大总结:面向过程的编程认为,数据和数据操作是分开的。然而当struct进入面向对象的c++时,其特性也有了新发展,就拿上面的错误函数来说,在c++中就能运行,因为在c++中认为数据和数据对象是一个整体,不应该分开,这就是struct在c和c++两个时代的差别。

3、什么情况下使用线程,多线程有什么优点?

出现的原因:
为了解决负载均衡问题,充分利用CPU资源.为了提高CPU的使用率,采用多线程的方式去同时完成几件事情而不互相干扰.为了处理大量的IO操作时或处理的情况需要花费大量的时间等等,比如:读写文件,视频图像的采集,处理,显示,保存等
好处:
(1)使用线程可以把占据时间长的程序中的任务放到后台去处理
(2)在一些等待的任务实现上如用户输入,文件读取和网络收发数据等,线程就比较有用了.
(3)程序的运行效率可能会提高
(4)用户界面更加吸引人,这样比如用户点击了一个按钮去触发某件事件的处理,可以弹出一个进度条来显示处理的进度

多线程的缺点:

(1)如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换.
(2)更多的线程需要更多的内存空间
(3)线程中止需要考虑对程序运行的影响.
(4)通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生
补充
四核指的是其采用的CPU有4颗核心。以前的CPU都是单核的,只有一个核心,就叫单核CPU。

**

4、如何让一个局部变量的生命周期边长?

**
static

5、c++内存分配方式有几种?

(1)堆heap:程序员手动分配和释放的,malloc/free,new/delete

(2)栈stack:由编译器自动分配和释放,用于存放局部变量和参数

(3)全局/静态区:存放全局变量和静态变量,在程序编译时分配

(4)文字常量区:存放常量字符串
(5)程序代码区:存放函数体的二进制代码

6、c++的几大特性

(1)继承
优点:继承减少了重复的代码、继承是多态的前提、继承增加了类的耦合性;
(2)多态
定义:多态性是指对不同类的对象发出相同的消息将会有不同的实现
C++有两种多态,称为动多态(运行期多态)和静多态(编译器多态)
(1)静多态主要是通过模板来实现
(2)而动多态是通过虚函数来实现的。即在基类中存在虚函数(一般为纯虚函数)子类通过重载这些接口
优点:大大提高了代码的可复用性;提高了了代码的可维护性,可扩充性;
(3)封装
定义:隐藏类的属性和实现细节,仅仅对外提供接口
(1)封装性实际上是由编译器去识别关键字public、private和protected来实现的,体现在类的成员可以有公有成员(public),私有成员(private),保护成员(protected)。
(2)私有只有类内才能访问
(3)保护成员是只有该类的成员函数和该类的派生类才可以访问的
(4)公有成员是封装体与外界的一个接口,类体外的函数可以访问公有成员

7、malloc与new的区别

(1)malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存
(2)new/delete执行的时候同时调用构造和析构
(3)new是保留字,不需要头文件支持.malloc需要头文件库函数支持.
(4)new 建立的是一个对象,malloc分配的是一块内存.
简而言之:
new 是一个操作符,可以重载
malloc是一个函数,可以覆盖
new 初始化对象,调用对象的构造函数,对应的delete调用相应的析构函数
malloc仅仅分配内存,free仅仅回收内存

例子
char * b = (char*)malloc(sizeof(char))
Button* BtnTitle= new Button(this);

8、sizeof和strlen区别

(1)sizeof是一个操作符,strlen是库函数;

(2)sizeof的参数可以是数据的类型,也可以是变量,而strlen只能以结尾为’\0’的字符串做参数;
(3)编译器在编译时就计算出了sizeof的结果。而strlen函数必须在运行时才能计算出来。
(4)sizeof计算的是数据类型占内存的大小,而strlen计算的是字符串实际的长度;
(5)数组做sizeof的参数不退化,传递给strlen就退化为指针了。

9、数据库select分页

10、面向对象比面向过程有什么优势

(1)面向对象和面向过程本来就是人类认知的过程。
(2)易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护,面向过程可重用性差,数据安全性差,难以开发大型软件和图形界面的应用软件
总结:面向对象更适合于需求不断变化的应用软件,而面向过程更适合需求稳定但要求质量和效率的底层软件

11、讲一讲多态性:前面讲过

12、 野指针

就是声明 而没有初始化或者说是没有开辟空间,用if (p != NULL)是识别不出来的。不同于空指针 =NULL

13、指针和引用的区别

引用的定义:
引用是给另外一个变量起别名,绑定一个变量,所以引用不会分配内存空间。对引用的所有操作,事实上都是作用在该引用所绑定的对象上
二者的区别:
(1)指针是一个实体,需要分配内存空间。引用只是变量的别名,不需要分配内存空间
(2)引用在定义的时候必须进行初始化,并且不能够改变(引用是针对已经存在的某个单元格进行二次命名,所以单元格必须先存在)。指针在定义的时候不一定要初始化,并且指向的空间可变。
(3)有多级指针,但是没有多级引用,只能有一级引用
(4)指针和引用的自增运算结果不一样。(指针是指向下一个空间,引用时引用的变量值加1)
(5)sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小。
(6)引用访问一个变量是直接访问,而指针访问一个变量是间接访问。
第六点的举例:
int a=1;
char* p=&a; 这边的是指p为指针类型
char
&b=p;这边char*是指引用的类型指针,指向char类型的空间。&是说明b是别名。
printf("%d",p);这边的是取值的意思,单独的p是地址。所有说是间接访问

14、队列和栈的区别

(1)规则不同
1. 队列:先进先出(First In First Out)FIFO想像成一个山峰
2. 栈:先进后出(First In Last Out )FILO
(2)对插入和删除操作的限定不同

   1. 队列:只能在表的一端进行插入,并在表的另一端进行删除;

   2. 栈:只能在表的一端插入和删除。

(3)遍历数据速度不同

   1. 队列:基于地址指针进行遍历,而且可以从头部或者尾部进行遍历,但不能同时遍历,无需开辟空间,因为在遍历的过程中不影响数据结构,所以遍历速度要快;

   2. 栈:只能从顶部取数据,也就是说最先进入栈底的,需要遍历整个栈才能取出来,而且在遍历数据的同时需要为数据开辟临时空间,保持数据在遍历前的一致性。

15、局部变量和全局变量可以重名么

在程序中如果出现了相同的两个变量,一个是局部变量,一个
是全局变量,编译可以通过,但是打印出的值是局部变量的
值,如果想打印全局变量的值的话,在全局变量之前加上“::”
就可以了。

16、析构函数的作用

析构函数是对象被销毁时,系统最后调用的一个函数,一般用于扫尾工作。一般成员变量里有指针时要写,因为这些指针指的空间一般是用new运算符分配的,不会随着对象的销毁而释放,因为系统只会自己释放那个指针用来存地址的空间,它指的那个空间很可能就孤立了,别人也再也指不过去了,所以要手动释放。

17、虚析构函数有什么作用

总的来说虚析构函数是为了避免内存泄露,而且是当子类中会有指针成员变量时才会使用得到的。也就说虚析构函数使得在删除指向子类对象的基类指针时可以调用子类的析构函数达到释放子类中堆内存的目的,而防止内存泄露的.

18、构造函数和析构函数调用的顺序

基类构造函数、对象成员构造函数(就是成员有对象 窗口有按钮对象的意思)、派生类本身的构造函数
派生类本身的析构函数、对象成员析构函数、基类析构函数(与构造顺序正好相反)

19、多态的机制是如何实现的。

原理也很简单,父类或者接口定义的引用变量可以指向子类或者具体实现类的实例对象,由于程序调用方法是在运行期才动态绑定的,那么引用变量所指向的具体实例对象在运行期才确定。所以这个对象的方法是运行期正在内存运行的这个对象的方法而不是引用变量的类型中定义的方法。

20、静态多态、动态多态

上边有讲

21、构造函数的特点

(1)构造函数名与类名相同,且没有返回值
(2)由系统在创建对象时自动调用的
(3)构造函数内容一般是初始化数据语句,但也可以包含其他的语句
(4)创建对象时必须执行一个构造函数,否则系统无法创建对象。如果用户自己没有定义构造函数,系统会自动提供一个构造函数,称之为默认的构造函数

22、Qt是什么

Qt是一个跨bai平台的C++图形用户界面应用程序框架。du它提供给应用zhi程序开发者建立艺术级的图形用dao户界面所需的所用功能。Qt是完全面向对象的,很容易扩展,并且允许真正地组件编程。

23、容器的分类 vector、list的区别

http://www.cnblogs.com/xkfz007/articles/2534249.html
首先知道什么是容器:在数据存储上,有一种对象类型,它可以持有其它对象或指向其它对像的指针,这种对象类型就叫做容器。很简单,容器就是保存其它对象的对 象,当然这是一个朴素的理解

(1) 在STL中基本容器有: vector、list、deque、set、map
(2)set 和map都是无序的保存元素,只能通过它提供的接口对里面的元素进行访问
(3)set :集合, 用来判断某一个元素是不是在一个组里面,使用的比较少
(4)map :映射,相当于字典 ,把一个值映射成另一个值,如果想创建字典的话使用它好了
(5)vector就是动态数组.它也是在堆中分配内存,元素连续存放,有保留内存,如果减少大小后,内存也不会释放.如果新值>当前大小时才会再分配内存.
(6)list就是双向链表 ,元素也是在堆中存放, 每个元素都是放在一块内存中,它的内存空间可以是不连续的,通过指针来进行数据的访问,这个特点使得它的随机存取变的非常没有效率 ,因此它没有提供[]操作符的重载。但由于链表的特点,它可以以很好的效率支持任意地方的删除和插入。list没有空间预留习惯 ,所以每分配一个元素都会从内存中分配,每删除一个元素都会释放它占用的内存.
(7)deque是一个双端队列,也是在堆中保存内容的,每个堆保存好几个元素,然后堆和堆之间有指针指向,看起来像是list和vector的结合品.可以让你在前面快速地添加删除元素,或是在后面快速地添加删除元素,然后还可以有比较高的随机访问速度,和vector的效率相差无几,它支持在两端的操作

因此在实际使用时,如何选择这三个容器中哪一个,应根据你的需要而定,一般应遵循下面
的原则:
(1)如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector
(2)如果你需要大量的插入和删除,而不关心随即存取,则应使用list
(3)如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque。

24、访问容器的方式

下标 重载符[]
vertor a;
vertor::iterator it;
for(vector::size_type i = 0;i < a.size();++i)
{
a[i];
}

迭代器的方式
list<Correct*>* list_Correct=new list<Correct*>;
list<Correct*>::iterator it;
for(it=list_Correct->begin();it!=list_Correct->end();it++)
{
(*it)->role 【->代表当前对象!的!…】
}

25define 和 const的差别

(1)就起作用的阶段而言:#define是在编译的预处理阶段起作用(在预处理阶段进行替换),而const是在编译运行的时候起作用(const修饰的只读变量是在编译的时候确定其值)

(2)就起作用的方式而言:#define只是简单的字符串替换,没有类型检查。而const有对应的类型,是要进行判断的,可以避免一些低级的错误

(3)就存储方式而言:#define只是进行展开,有多少地方使用,就替换多少次。它定义的宏常量在内存中存若干个备份;const定义的只读变量在程序中只有一份备份

(4)从代码调试的方便程度而言:const常量可以进行调试的,define是不能进行调试的,因为在预编译阶段就已经进行替换了

(5)就内存分配而言:编译器通常不为普通的const只读变量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高

猜你喜欢

转载自blog.csdn.net/weixin_44972997/article/details/107161324
今日推荐