c/c++面试题汇总(4)

来源:互联网 发布:网络棋牌赌博如何举报 编辑:程序博客网 时间:2024/05/24 01:42

1. 设置地址为0x67a9的整型变量的值为0xaa66 

int *ptr;  

ptr = (int *)0x67a9;  

*ptr = 0xaa66;  

说明:这道题就是强制类型转换的典型例子,无论在什么平台地址长度和整型数据的长度是一样的,即一个整型数据可以强制转换成地址指针类型,只要有意义即可。

2.面向对象的三大特征 

面向对象的三大特征是封装性、继承性和多态性: 

封装性:将客观事物抽象成类,每个类对自身的数据和方法实行protection(private, protected,public)。

继承性:广义的继承有三种实现形式:实现继承(使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的

外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。 

多态性:是将父类对象设置成为和一个或更多它的子对象相等的技术。用子类对象给父类对象赋值之后,父类对象就可以根据当前

赋值给它的子对象的特性以不同的方式运作。

3.C++的空类有哪些成员函数 

 缺省构造函数、 缺省拷贝构造函数、缺省析构函数、缺省赋值运算符、 缺省取址运算符、 缺省取址运算符 const。(只有在使用时,编译器才会去定义他们)。

4.谈谈你对拷贝构造函数和赋值运算符的认识 

拷贝构造函数和赋值运算符重载有以下两个不同之处: (1)拷贝构造函数生成新的类对象,而赋值运算符不能。 (2)由于拷贝

构造函数是直接构造一个新的类对象,所以在

初始化这个对象之前不用检验源对象是否和新建对象相同。而赋值运算符则需要这个操作,另外赋值运算中如果原来的对象中有内

存分配要先把内存释放掉 

注意:当有类中有指针类型的成员变量时,一定要重写拷贝构造函数和赋值运算符,不要使用默认的。 

5.用C++设计一个不能被继承的类

待定。

6.简述多态实现的原理 
编译器发现一个类中有虚函数,便会立即为此类生成虚函数表 vtable。虚函数表的各表项为指向对应虚函数的指针。编译器还会在

此类中隐含插入一个指针vptr(对vc编译器来说,它插在类的第一个位置上)指向虚函数表。调用此类的构造函数时,在类的构造

函数中,编译器会隐含执行vptr与vtable的关联代码,将vptr指向对应的vtable,将类与此类的vtable联系了起来。另外在调用类

的构造函数时,指向基础类的指针此时已经变成指向具体的类的this指针,这样依靠此this指针即可得到正确的vtable,。如此才

能真正与函数体进行连接,这就是动态联编,实现多态的基本原理。 

注意:一定要区分虚函数,纯虚函数、虚拟继承的关系和区别。牢记虚函数实现原理,因为多态C++面试的重要考点之一,而虚函数

是实现多态的基础。

7.链表和数组有什么区别 
数组和链表有以下几点不同: 

(1)存储形式:数组是一块连续的空间,声明时就要确定长度。链表是一块可不连续的动态空间,长度可变,每个结点要保存相邻结点指针。 
(2)数据查找:数组的线性查找速度快,查找操作直接使用偏移地址。链表需要按顺序检索结点,效率低。 
(3)数据插入或删除:链表可以快速插入和删除结点,而数组则可能需要大量数据移动。 
(4)越界问题:链表不存在越界问题,数组有越界问题。 
说明:在选择数组或链表数据结构时,一定要根据实际需要进行选择。数组便于查询,链表便于插入删除。数组节省空间但是长度固定,链表虽然变长但是占了更多的存储空间。

8.简述队列和栈的异同 
队列和栈都是线性存储结构,但是两者的插入和删除数据的操作不同,队列是“先进先出”,栈是“后进先出”。

9.谈谈你对编程规范的理解或认识 

编程规范可总结为:程序的可行性,可读性、可移植性以及可测试性。 

说明:这是编程规范的总纲目,面试者不一定要去背诵上面给出的那几个例子,应该去理解这几个例子说明的问题,想一想,自己

如何解决可行性、可读性、可移植性以及可测试性这几个问题,结合以上几个例子和自己平时的编程习惯来回答这个问题。

10.short i = 0; i = i + 1L;这两句有错吗 

代码一是错的,代码二是正确的。 说明:在数据安全的情况下大类型的数据向小类型的数据转换一定要显示的强制类型转换

11.&&和&、||和|有什么区别 

(1)&和|对操作数进行求值运算,&&和||只是判断逻辑关系

(2)&&和||在在判断左侧操作数就能确定结果的情况下就不再对右侧操作数求值

12.写一个“标准”宏MIN 

写一个“标准”宏MIN,这个宏输入两个参数并且返回较小的一个。 

【答案】 #define min(a,b)((a)<=(b)?(a):(b)) 

注意:在调用时一定要注意这个宏定义的副作用,如下调用:((++*p)<=(x)?(++*p):(x)。p指针就自加了两次,违背了MIN的本意。 
13.typedef和define有什么区别 

(1)用法不同:typedef用来定义一种数据类型的别名,增强程序的可读性。define主要用来定义常量,以及书写复杂使用频繁的宏。 
(2)执行时间不同:typedef是编译过程的一部分,有类型检查的功能。define是宏定义,是预编译的部分,其发生在编译之前,

只是简单的进行字符串的替换,不进行类型的检查。 

(3)作用域不同:typedef有作用域限定。define不受作用域约束,只要是在define声明后的引用都是正确的。 

(4)对指针的操作不同:typedef和define定义的指针时有很大的区别。 

注意:typedef定义是语句,因为句尾要加上分号。而define不是语句,千万不能在句尾加分号

14.流操作符重载为什么返回引用 

在程序中,流操作符>>和<<经常连续使用。因此这两个操作符的返回值应该是一个仍旧支持这两个操作符的流引用。其他的数据类

型都无法做到这一点。 

注意:除了在赋值操作符和流操作符之外的其他的一些操作符中,如+、-、*、/等却千万不能返回引用。因为这四个操作符的对象

都是右值,因此,它们必须构造一个对象作为返回值

15.简述指针常量与常量指针区别 

指针常量是指定义了一个指针,这个指针的值只能在定义时初始化,其他地方不能改变。常量指针是指定义了一个指针,这个指针

指向一个只读的对象,不能通过常量指针来改变这个对象的值。 指针常量强调的是指针的不可改变性,而常量指针强调的是指针对

其所指对象的不可改变性。 注意:无论是指针常量还是常量指针,其最大的用途就是作为函数的形式参数,保证实参在被调用函数

中的不可改变特性

16.谈谈你对面向对象的认识 

面向对象可以理解成对待每一个问题,都是首先要确定这个问题由几个部分组成,而每一个部分其实就是一个对象。然后再分别设

计这些对象,最后得到整个程序。传统的程序设计多是基于功能的思想来进行考虑和设计的,而面向对象的程序设计则是基于对象

的角度来考虑问题。这样做能够使得程序更加的简洁清晰。 

说明:编程中接触最多的“面向对象编程技术”仅仅是面向对象技术中的一个组成部分。发挥面向对象技术的优势是一个综合的技术问题,不仅需要面向对象的分析,设计和编程技术,而且需要借助必要的建模和开发工具

17.构造函数能否为虚函数 

构造函数不能是虚函数。而且不能在构造函数中调用虚函数,因为那样实际执行的是父类的对应函数,因为自己还没有构造好。析

构函数可以是虚函数,而且,在一个复杂类结构中,这往往是必须的。析构函数也可以是纯虚函数,但纯虚析构函数必须有定义

体,因为析构函数的调用是在子类中隐含的。 

说明:虚函数的动态绑定特性是实现重载的关键技术,动态绑定根据实际的调用情况查询相应类的虚函数表,调用相应的虚函数

18.如何避免“野指针” 

“野指针”产生原因及解决办法如下: 

(1)指针变量声明时没有被初始化。解决办法:指针声明时初始化,可以是具体的地址值,也可让它指向NULL。 

(2)指针 p 被 free 或者 delete 之后,没有置为 NULL。解决办法:指针指向的内存空间被释放后指针应该指向NULL。 

(3)指针操作超越了变量的作用范围。解决办法:在变量的作用域结束前释放掉变量的地址空间并且让指针指向NULL。 

注意:“野指针”的解决方法也是编程规范的基本原则,平时使用指针时一定要避免产生“野指针”,在使用指针前一定要检验指

针的合法性。 

19.常引用有什么作用 

常引用的引入主要是为了避免使用变量的引用时,在不知情的情况下改变变量的值。常引用主要用于定义一个普通变量的只读属性

的别名、作为函数的传入形参,避免实参在调用函数中被意外的改变。 说明:很多情况下,需要用常引用做形参,被引用对象等效

于常对象,不能在函数中改变实参的值,这样的好处是有较高的易读性和较小的出错率

20.数组名和指针的区别 

请写出以下代码的打印结果: 

#include <iostream.h> 

#include <string.h>

 void main(void) 

{

  char str[13]="Hello world!";

  char *pStr="Hello world!";   
  cout<<sizeof(str)<<endl;  

  cout<<sizeof(pStr)<<endl;  

  cout<<strlen(str)<<endl;  

  cout<<strlen(pStr)<<endl;  

  return; 
}

结果:13,4,12,12

一定要记得数组名并不是真正意义上的指针,它的内涵要比指针丰富的多。但是当数组名当做参数传递给函数后,其失去原来的含

义,变作普通的指针。另外要注意sizeof不是函数,只是操作符。

21.如何截取键盘的响应,让所有的‘a’变成‘b’?

键盘钩子SetWindowsHookEx

22.存储过程是什么?有什么用?有什么优点?

    存储过程(Stored Procedure)是一组为了完成特定功能的SQL 语句集,经编译后存储在数据库。中用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程用于实现频繁使用的查询、业务规则、被其他过程使用的公共例行程序

23.网络编程中设计并发服务器,使用多进程与多线程 ,请问有什么区别?

1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
区别:两者都可以提高程序的并发度,提高程序运行效率和响应时间。线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。

存储过程在创建时即在服务器上进行编译,所以执行起来比单个 SQL 语句快

24.In C++, what does "explicit" mean? what does "protected" mean?

c++中的explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,在某些情况下,我们要求类的使用者必须显示调用类的构造函数时就需要使用explicit,反之默认类型转换可能会造成无法预期的问题。

protected控制的是一个函数对一个类的成员(包括成员变量及成员方法)的访问权限。protected成员只有该类的成员函数及其派生类的成员函数可以访问

25.在c++的一个类中声明一个static成员变量有没有用?

在C++类的成员变量被声明为static(称为静态成员变量),意味着它为该类的所有实例所共享,也就是说当某个类的实例修改了该静态成员变量,也就是说不管创建多少对象,static修饰的变量只占有一块内存。其修改值为该类的其它所有实例所见;而类的静态成员函数也只能访问静态成员(变量或函数)。

static是加了访问控制的全局变量,不被继承。

26.如何实现一个非阻塞的socket?

后期会详细讲解

27.解释一下多播(组播)和广播的含义?

组播:主机之间“一对一组”的通讯模式,也就是加入了同一个组的主机可以接受到此组内的所有数据,网络中的交换机和路由器只向有需求者复制并转发其所需数据。主机可以向路由器请求加入或退出某个组,网络中的路由器和交换机有选择的复制并传输数据,即只将组内数据传输给那些加入组的主机。

广播:主机之间“一对所有”的通讯模式,网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(不管你是否需要)

28.编写strcat函数

char * __cdecl strcat (char * dst, const char * src)

{

char * cp = dst;-----------方便执行完赋值给其他变量

while( *cp )

cp++; /* find end of dst */

while( *cp++ = *src++ ) ; /* Copy src to end of dst */

return( dst ); /* return dst */

}

29.C++中为什么用模板类。

 (1)可用来创建动态增长和减小的数据结构

(2)它是类型无关的,因此具有很高的可复用性。

(3)它在编译时而不是运行时检查数据类型,保证了类型安全

(4)它是平台无关的,可移植性

(5)可用于基本数据类型

 

30.CSingleLock是干什么的。

答:同步多个线程对一个数据类的同时访问


1 0
原创粉丝点击