面试题目积累

19.C++多态的实现原理
对于虚函数调用来说,每一个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。所以在程序中,不管你的对象类型如何转换,但该对象内部的虚表指针是固定的,所以呢,才能实现动态的对象函数调用,这就是C++多态性实现的原理。

20.重载和重写的区别
重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
重写:是指子类重新定义父类虚函数的方法。
从实现原理上来说:
重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;和function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_func、str_func。对于这两个函数的调用,在编译器间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关! 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。

21.多态的作用
1. 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;
2. 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。

22.为什么构造函数不能是虚函数
因为每一个拥有虚成员函数的类都有一个指向虚函数表的指针。对象通过虚函数表里存储的虚函数地址来调用虚函数。那虚函数表指针是什么时候初始化的呢?当然是构造函数。当我们通过new来创建一个对象的时候,第一步是申请需要的内存,第二步就是调用构造函数。试想,如果构造函数是虚函数,那必然需要通过vtbl来找到虚构造函数的入口地址,显然,我们申请的内存还没有做任何初始化,不可能有vtbl的。因此,构造函数不能是虚函数。

23.虚函数和纯虚函数的区别
虚函数必须是基类的非静态成员函数,其访问权限可以是protected和public。在很多种情况下,基类中不能对虚函数给出有意义的实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做,这就是纯虚函数的作用。纯虚函数是虚函数的一个子集,用于抽象类,含有纯虚函数的类就是抽象类,它不能生成对象。

24.什么是this指针
this指针是一个隐含的指针,它是指向对象本身的,表示当前对象的饿地址。在一个非静态的成员里面,this关键字就是一个指针,指向该函数的这次调用所针对的那个对象。

25.何时使用this指针
当对一个对象调用成员函数时,编译程序先将对象的地址赋给this指针,然后调用成员函数,每次成员函数存取数据成员时,由隐含作用this指针。而通常不去显示地使用this指针来引用数据成员。同样也可以使用*this来标识调用该成员函数的对象。

26.引用和值传递的区别
值传递传递的是一个值的副本。函数对形参的操作不会影响实参的值。而引用传递传递的是引用的对象的内存地址,函数对形参的操作会影响实参的值,实参的值将会随着形参值的更改而同样进行更改。

27.面向对象和面向过程的区别
面向过程是一种以过程为中心的编程思想,以算法进行驱动。面向对象是一种以对象为中心的思想,以消息进行驱动。面向过程编程语言的组成为:程序=算法+数据,面向对象编程语言的组成为:程序=对象+消息

28.试从调度性,并发性,拥有资源及系统开销方面对进程和线程进行比较.
a. 调度性。在传统的操作系统中,拥有资源的基本单位和独立调度、分派的基本单位都是进程,在引入线程的OS中,则把线程作为调度和分派的基本单位,而把进程作为资源拥有的基本单位;
b. 并发性。在引入线程的OS中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间,亦可并发执行,因而使OS具有更好的并发性;
c. 拥有资源。无论是传统的操作系统,还是引入了线程的操作系统,进程始终是拥有资源的一个基本单位,而线程除了拥有一点在运行时必不可少的资源外,本身基本不拥有系统资源,但它可以访问其隶属进程的资源;
d. 开销。由于创建或撤销进程时,系统都要为之分配和回收资源,如内存空间等,进程切换时所要保存和设置的现场信息也要明显地多于线程,因此,操作系统在创建、撤消和切换进程时所付出的开销将显著地大于线程。

29.如何访问静态成员
静态成员可以独立访问,不需要创建类的实例,它不能用实例来进行调用。类的静态方法只能访问类的静态成员。

30.什么时候会使用拷贝构造函数
1.一个对象以值传递的方式传入函数体
2.一个对象以值传递的方式从函数返回
3.一个对象需要通过另外一个对象进行初始化

31.什么是静态函数?如何使用静态函数?
静态函数是使用static修饰符修饰的函数,静态函数没有this指针,只能访问静态变量。在类中如果函数调用的结果不会访问或者修改任何对象数据成员这样的成员声明为静态成员函数比较好。

32.函数重载与作用域
函数重载是指在相同的作用域中,具有相同的名称而形参列表不同的多个函数

33.内存管理的方式
内存管理是操作系统中的重要部分,操作系统中的内存管理指的是操作系统中管理内存使用的功能。主要包括向用户程序提供内存逻辑地址,并完成逻辑地址到物理地址的转换,完成用户程序的载入工作,采用各种技术提高内存使用率,保护内存及其安全等功能。内存管理模式有7种,包括无管理模式、单一分区、固定分区、可变分区、页、段和段页,目前最常用的是页式管理。

34.作业调度算法有哪些
作业调度的常用算法有先来先服务算法、最短作业优先算法、最高响应比优先算法、基于优先数调度算法。

  1. 作业一般有哪些状态
    一个作业从进入系统到它运行结束,一般要经历4个状态,分别是进入状态,后备状态,运行状态和完成状态。

36.对拷贝构造函数的深拷贝和浅拷贝
深拷贝意味着拷贝了资源和指针,而浅拷贝只是拷贝了指针,没有拷贝资源。这样会使得两个指针指向同一份资源,造成对同一份资源析构两次,程序崩溃。

37.如何实现多态?父类和子类的继承关系如何?
多态的基础是继承,需要虚函数的支持,C++中多态有下面3种实现方式:1.使用函数重载 2.使用模板函数 3.使用虚函数
子类继承父类的大部分资源,不能继承的有构造函数、析构函数、拷贝构造函数、operator=函数、友元函数等。

38.例举几种进程的同步机制
原子操作、信号量机制、自旋锁、管程、回合、分布式系统

39.进程之间通信的途径
共享存储系统、消息传递系统、管道:以文件系统为基础

40.进程死锁的原因
死锁是指在两个或多个并发进程中,如果每个进程持有某种资源而又等待别的进程释放它们现在保持着的资源,否则就不能向前推进。
归结为:系统资源不足,进程推进顺序非法

41.操作系统中进程调度策略有哪几种
先来先服务、优先级、时间片轮转和多级反馈

  1. 类的静态成员和非静态成员有何区别?
    静态变量使用static修饰符进行声明,在类被实例化时创建。
    非静态变量在对象被实例化时创建,通过对象进行访问一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值。静态函数的实现里不能使用非静态成员,例如非静态变量、非静态函数等。
    类的静态成员每个类只有一个,非静态成员每个对象只有一个。

43.重载和重写的区别
1. 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)
2. 重写:是指子类重新定义父类虚函数的方法,和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据付给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出),因此,这样的函数地址是在运行期绑定的。

44.堆栈溢出一般是由什么原因导致的
堆栈溢出一般是循环的递归调用导致的。如果使用大数据结构的局部变量,也可能导致堆栈溢出。

45.为什么构造函数不能是虚函数
每一个拥有虚成员函数的类都有一个指向虚函数表的指针。对象通过虚函数表里存储的虚函数地址来调用虚函数。
我们调用构造函数的时候,创建虚函数表,当我们通过new来创建一个对象的时候,第一步是申请需要的内存,第二步就是调用构造函数。如果构造函数是虚函数,那必然需要通过vtbl来找到虚构造函数的入口地址,显然,我们申请的内存还没有做任何初始化,不可能有vtbl的。因此,构造函数不能是虚函数。

46.static和const关键字的作用
static关键字有如下作用:
1.函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍然维持上次的值
2.在模块内的static全局变量和static函数可以被模块内所有函数访问,但是不能够被模块外的其他函数访问。
3.在类中的static成员变量属于整个类所有,对类的所有对象只有一份拷贝。
4.在类中的static成员函数属于整个类所拥有,这个函数不接受this指针,因而只能访问类的static成员变量。

const关键字有如下作用:
(1)想要阻止一个变量被改变可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就再没有机会改变它了
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或者二者都为const
(3)在一个函数声明中,cosnt可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值。
(4)对于类的 成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的成员变量
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”

47.什么预编译,何时处理预编译?
预编译就是处理#开头的指令。
(1)总是使用不经常改动的大型代码体
(2)程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为预编译头

48.结构和联合有何区别
(1)结构和联合都是由多个不同的数据类型成员组成的。但是在任何同一时刻,联合中只存放了一个被选中的成员(所有成员共用一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。
(2)对于联合的不同成员赋值,将会对其他成员重写,原来成员的值就不存在了,而对于结构的不同成员赋值是互不影响的。

49.动态链接和静态链接的区别
静态链接就是在编译链接时直接将需要的执行代码拷贝到调用处,优点就是在程序发布的时候就不需要的依赖库,程序可以独立执行,但是体积可能会相对大一些。
动态链接就是在编译的时候不直接拷贝可执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定的代码时,去共享执行内存中已经加载的动态库可执行代码,最终达到运行时连接的目的。优点是多个程序可以共享同一段代码,而不需要在磁盘上存储多个拷贝,缺点是由于是运行时加载,可能会影响程序的前期执行性能。

  1. 虚拟内存的定义及实现方式。
    虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。与没有使用虚拟内存技术的系统相比,使用这种技术的系统使得大型程序的编写变得更容易,对真正的物理内存(例如RAM)的使用也更有效率。

51.线程同步几种方式。
线程同步的方式主要有以下四种:临界区(Critical Section)、互斥量(Mutex)、信号量(Semaphore)、事件(Event)的区别。
他们的主要区别和特点如下:
1)临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占。
2)互斥量:采用互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享
3)信号量:它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目
4)事 件: 通过通知操作的方式来保持线程的同步,还可以方便实现对多个线程的优先级比较的操作

52.哪些情况下,会由用户态切换到内核态
通常来说,以下三种情况会导致用户态到内核态的切换:
1)系统调用
这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作,比如前例中fork()实际上就是执行了一个创建新进程的系统调用。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
2)异常
当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
3)外围设备的中断
当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。
这3种方式是系统在运行时由用户态转到内核态的最主要方式,其中系统调用可以认为是用户进程主动发起的,异常和外围设备中断则是被动的。

53.使用线程是如何防止出现大的波峰。
答:意思是如何防止同时产生大量的线程,方法是使用线程池,线程池具有可以同时提
高调度效率和限制资源使用的好处,线程池中的线程达到最大数时,其他线程就会排队
等候。

54.类的静态成员和非静态成员有何区别?
答:类的静态成员每个类只有一个,静态成员为所有类的实例对象共享,静态成员有静态成员变量和静态成员函数,静态成员变量使用前必须初始化,静态成员变量可以被静态成员函数和非静态成员函数访问,而静态成员函数只能访问静态成员变量,因为静态成员函数属于类,其没有this指针。非静态成员每个对象都有一个。

55.static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
答:static全局变量与普通的全局变量的区别:前者在主函数之前就要被初始化,而后者没有要求,两者的作用域不同,前者的作用域只限于子模块(子程序或函数),而后者在整个程序中都可以被使用。
static局部变量和普通局部变量的区别:一个函数中的static变量值会保留到该函数下次调用来改变它,而后者在函数运行完后就被销毁了,两者的存储区域不同,前者存储在静态区(全局区),后者的内存位于堆栈上。
static函数与普通函数:static函数可以直接通过类调用,不需要在此之前实例化对象,而普通函数需要先定义对象。static函数不能用非static成员。static在循环中定义并赋值时,定义过程只进行一次,而不是每个循环1次。

56.static的用途?
答:(1)函数体内的静态变量,其值在函数的调用过程中保持不变。跟局部变量的区别。
(2)在函数体外定义的静态变量,限制了它的使用范围只在于该子模块,该子模块内的函数都能访问它,但是子模块外不能访问,实际就类似于是一个本地的全局变量。与一般全局变量的区别。
(3)类的静态成员函数。
本质上来说,static就是声明了对象的生成期,限制了对象的作用域。
或 (1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只能被分配一次,因此其值在下次函数调用时仍维持上次的值。
(2)在模块内的static全局变量可以被模块内的所有函数访问,但不能被模块外其他函数访问。
(3)在模块内的static函数只可被这一模块内的其他函数调用,这个函数的使用范围被限制在声明它的模块。
(4)在类中的static成员变量属于整个类所有,对类的所有对象只有一份拷贝。
(5)在类中的static成员函数属于整个类所有,这个函数不接受this指针,因而只能访问类的static成员变量。

57.C++中哪些函数不能被声明为虚函数?
答:普通函数(非成员函数),构造函数,内联成员函数、静态成员函数、友元函数。
(1)虚函数用于基类和派生类,普通函数所以不能
(2)构造函数不能是因为虚函数采用的是虚调用的方法,允许在只知道部分信息的情况的工作机制,特别允许调用只知道接口而不知道对象的准确类型的方法,但是调用构造函数即使要创建一个对象,那势必要知道对象的准确类型。
(3)内联成员函数的实质是在调用的地方直接将代码扩展开
(4)继承时,静态成员函数是不能被继承的,它只属于一个类,因为也不存在动态联编等
(5)友元函数不是类的成员函数,因此也不能被继承

58.什么是“引用”?申明和使用“引用”要注意哪些问题?
答:引用就是某个目标变量的“别名”(alias),对引用的操作与对变量直接操作效果完全相同。申明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,不能再把该引用名作为其他变量名的别名。声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元。不能建立数组的引用。

59.避免死锁的方法
通过破除死锁的四个必要条件之一,来预防死锁的产生,有两种方法,一种是当其申请的资源得不到满足时,也必须放弃原先占有的资源;另一种方法是只适用于申请资源的进程优先级比占有资源的进程优先级高时如果一个进程申请的资源被其它进程占有,而申请进程的优先级较高,那么它可以强迫占有资源的进程放弃。
仔细对资源进行分配,以避免死锁。

60.什么是智能指针?
智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。当然,智能指针还不止这些,还包括复制时可以修改源对象等。智能指针根据需求不同,设计也不同(写时复制,赋值即释放对象拥有权限、引用计数等,控制权转移等)。auto_ptr 即是一种常见的智能指针。智能指针通常用类模板实现。

61.extern关键字的作用
(1)声明外部变量
(2)在C++文件中调用C语言编译的文件

62.拷贝构造函数作用及用途?什么时候需要自定义拷贝构造函数?
答: (1)、在C++中,有下面三种对象需要拷贝的情况:
a、一个对象以值传递的方式传入函数体
b、一个对象以值传递的方式从函数返回
c、一个对象需要通过另外一个对象进行初始化
以上的情况就需要拷贝构造函数的调用。
(2)、当类中的数据成员需要动态分配存储空间时,不可以依赖default copy constructor。当default copy
constructor被因编译器需要而合成时,将执行default memberwise copy语义。
此时如果类中有动态分配的存储空间时,将会发生惨重的灾情。
C++面试问与答攻略 2015/8/23
在需要时(包括这种对象要赋值、这种对象作为函数参数要传递、函数返回值为这种对象等情况),要考虑
到自定义拷贝构造函数。

63.C++中的转化机制?各适用于什么环境?dynamic_cast转换失败时,会出现什么情况?
答:对指针,返回NULL.对引用,抛出bad_cast异常more Effective C++
C++引入了4种类型转化操作符(cast operator):static_cast,const_cast,dynamic_cast和reinterpret_cast
使用方法与C语言中略有不同:
1. (type)expression; //这是C语言的
然后引入C++的:
1. static_cast(expression);//这是C++的

static_cast:static_cast基本上拥有与C旧式转型相同的威力和意义,以及相同的限制。但是,该类型转换操作符
不能移除常量性,因为有一个专门的操作符用来移除常量性。
const_cast:用来改变表达式中的常量性(constness)或者易变形(volatileness),只能用于此功能。
dynamic_cast:将指向基类basic class object的pointer或者reference转型为指向派生类derived(或这sibling
base)class object的pointer或者reference中,并且可以获知是否转型成功:如果转型失败,当转型对象是指针
的时候会返回一个null指针;当转型对象是reference会抛出一个异常exception。dynamic_cast无法应用在缺乏虚
函数的类型上,也不能改变类型的常量性。
此外,dynamic_cast还有一个用途就是找出被对象占用的内存的起始点。
reinterpret_cast:这个操作符的转换结果几乎总是和编译器平台相关,所以不具有移植性。reinterpret_cast的最
常用用途是转换“函数指针”类型,如下:
1. typedef void(*FuncPtr)();
2.
3. int doSomething();
4.
5. int main()
6. {
7. FuncPtr funcPtrArray[10];
8. funcPtrArray[0] = reinterpret_cast(&doSomething);
9. return 0;
10. }
通过reinterpret_cast强迫编译器了,并成功的将不同的类型的函数&doSomething转换为需要的类型。不过这个
操作符进行的转换动作不具有移植性(C++不保证所有的函数指针都能以此方式重新呈现),某些情况下这样的
转型可能会导致不正确的结果,所以这种操作不到万不得已不要使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值