C++面试题

C++面试题

1. C++的类和C里面的struct有什么区别?

答:structclass的区别在于C里面的struct没有定义方法,而C++的类是将不同类型的数据和与这些数据相关的操作封装在一起的集合体,包含了操作方法。

 

2. 请说出const#define相比,有何优点?

答:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。

有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。

 

3. 类成员函数的重载、覆盖和隐藏区别?

答:成员函数被重载的特征:相同的范围(在同一个类中);函数名字相同;参数不同;virtual关键字可有可无。

覆盖是指派生类函数覆盖基类函数,其特征是:函数名字相同;参数相同;范围不同(分别位于派生类与基类中);基类函数必须有 virtual 关键字。

“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类函数将被隐藏(注意别与重载混淆)。如果派生类的函数与基类函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类函数被隐藏(注意别与覆盖混淆)。

 

4. 堆和栈的区别?

答:栈是由编译器自动分配释放,用来存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

堆一般是由程序员分配释放,若程序员不释放,程序结束时可能由操作系统回收。

 

5. 面向对象的三个基本特征,并简单叙述之?

答:

封装:将客观事物抽象成类,每个类对自身的数据和方法实行访问权限保护(privateprotectedpublic)

继承:广义的继承有三种实现形式:实现继承、可视继承、接口继承。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种方式。

多态:是将父类对象设置成为和一个或多个他的子类对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给其父类类型的指针。

 

6. 构造函数可否是虚函数,为什么?析构函数呢,可否是纯虚的呢?

答:构造函数不能为虚函数,要构造一个对象,必须清楚地知道要构造什么,否则无法构造一个对象。析构函数可以为纯虚函数。

 

7. C++是不是类型安全的?

答:C++不是类型安全的。因为两个不同类型的指针之间可以强制转换(用reinterpret cast)。

 

8. 多态的作用?

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

 

9. 请找出下面代码中的错误。

void test ()

{

  char string[10];

  char* str1 = "0123456789";

  strcpy( string, str1 );

}

答:字符串str1需要11个字节才能存放下(包括末尾的’\0’),而string只有10个字节的空间,strcpy会导致数组越界。

 

10. 请找出下面代码中的错误。

void test(char* str1)

{

  char string[10];

  if( strlen( str1 ) <= 10 )

{

    strcpy( string, str1 );

  }

}

答:if(strlen(str1) <= 10)应改为if(strlen(str1) < 10),因为strlen的结果未统计’\0’所占用的1个字节。

 

11. 参数传递具体有哪几种方式?

   答:参数传递具体包括:值传递,指针传递和引用传递三种方式。

 

12. 重载和重写的区别?

答:首先从定义上来说:

重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。

重写:是指子类重新定义复类虚函数的方法。

其次从实现原理上来说:

重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。如,有两个同名函数:function func(p:integer):integer;function func(p:string):integer;。那么编译器做过修饰后的函数名称可能是这样的:int_funcstr_func。对于这两个函数的调用,在编译期间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关。

重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)。

 

13. 虚函数的本质和实现机制?

答:虚函数的本质就是通过基类访问派生类定义的函数。虚函数只能借助于指针或者引用来达到多态的效果。

 

14. 堆栈溢出一般是由什么原因导致的?

答:没有回收垃圾资源。

 

15. 关键字static的作用是什么?

答:在C语言中,关键字static有三个明显的作用:

  1. 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变。
  2. 在模块内,一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。
  3. 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。

 

16. 论述含参数的宏与函数的优缺点。

答:

宏的优点:执行效率高,宏的缺点:容易出错。

函数的优点:不容易出错,函数的缺点:执行效率低。

 

17. 解释局部变量、全局变量和静态变量的含义。

答:局部变量、全局变量和静态变量是相对于生命周期说的,全局变量伴随程序直到最后,局部变量离开了作用域就会销毁。静态变量分为静态局部变量和静态全局变量,它们的生命周期伴随程序直到最后,二者的区别在于可见性不同。

 

18. do……whilewhile……do有什么区别?

答:前一个循环一遍再判断,后一个判断以后再循环。

 

19. 队列和栈有什么区别?

答:队列先进先出,栈后进先出。

 

20. 用变量a给出下面的定义。

  a)一个整型数

  b)一个指向整型数的指针

  c)一个指向指针的的指针,它指向的指针是指向一个整型数

  d)一个有10个整型数的数组

  e)一个有10个指针的数组,该指针是指向一个整型数的

  f)一个指向有10个整型数数组的指针

  g)一个指向函数的指针,该函数有一个整型参数并返回整型数

  h)一个有10个指针的数组,该指针是指向一个函数的,该函数有一个整型参数并返回整型数。

   答:用变量a给出的定义如下:

 a int a;                 b int *a;

 c int **a;             d int a[10];

 e int *a[10];        f int (*a)[10];

 g int (*a)(int);     h int (*a[10])(int);

 

21. 全局变量和局部变量在内存中是否有区别?如果有,是什么区别?

答:全局变量储存在静态数据库,局部变量在堆栈。

 

22. int i=(j=4,k=8,l=16,m=32); printf(“%d”, i);该语句的输出结果是多少?

答:输出结果为:32

 

23. 局部变量能否和全局变量重名?

答:能,局部会屏蔽全局。如果要使用全局变量,需要使用"::"

局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如,在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。

 

24. 请写出下面代码的输出结果。

#include<stdio.h>

main()

{

  int a,b,c,d;

  a=10;

  b=a++;

  c=++a;

  d=10*a++;

  printf("bcd%d%d%d"bcd);

}

答:输出结果为:bcd1012120

 

25. 如果用VC开发程序,常见这么几个错误,C2001, C2005, 这些错误的原因是什么。

答:在学习VC++的过程中,遇到的C2001错误的错误消息主要为:unresolved external symbol(不确定的外部符号)。如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。

一般来说,发生该错误的原因有两个:一是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。

编程中也经常能遇到C2005错误,即重复定义错误,其实LNK2005错误并不是一个很难解决的错误。

 

26. 请说明虚函数的本质和实现机制

答:虚函数的本质是通过基类访问派生类定义的函数。虚函数只能借助于指针或者引用来达到多态效果。

 

27. 分别说出描述点对象、大小对象和矩形对象的类名称。

   答:CPoint类,CSize类和CRect类。

 

28. 异步socket编程中,send不出数据的原因是什么,你是怎么处理的?

答:异步socket编程中,send不出数据的原因共有两个,分别是:TCP下连接断开了和该socket处在阻塞状态(也就是说在发送数据中)。处理的办法就是记录下该SOCKET的状态,当状态为阻塞的时间,放入缓冲,当该SOCKET再次可写时,发送。

 

29. 描述并比较以下对象:事件,信标,临界区,互斥对象。

答:这些对象都是用于线程同步的对象。

临界区:一种保证在某一时刻只有一个线程能访问数据的简便办法。它只可以在同一进程内部使用。主要API函数有,产生临界区:InitializeCriticalSection,删除临界区:DeleteCriticalSection,进入临界区:EnterCriticalSection,退出临界区:Le***eCriticalSection

互斥对象:互斥对象跟临界区相似,但它不仅仅能够在同一应用程序不同  线程中实现资源的安全共享,而且可以在不同应用程序的线程之间实现对资源的安全共享,当然下面两者也有这个特点。主要API函数有,创建互斥量: CreateMutex,打开一个存在的互斥量: OpenMutex,释放互斥量的使用权:ReleaseMutex,关闭互斥量: CloseHandle

信标:使用信号量(信标)最重要用途是:信号允许多个线程同时使用共享资源,它指出了同时访问共享资源的线程最大数目。它的API函数和使用方法都与互斥对象相似,如创建信号灯:CreateSemaphore,传入的参数可以指定信号灯的初始值。

事件:用来通知其他进程/线程某件操作已经完成。API函数有创建,打开事件对象等,特殊点的是可以用函数SetEvent人工设置事件为有无信号状态,因此创建事件对象时可以有两种方式,一种为自动重置,一种为人工重置。只有人工重置方式创建的事件对象才能正确使用函数SetEvent

 

30. 异步IO和同步IO有什么区别?

答:异步IO当函数返回时不一定就完成了IO操作,而同步IO已经完成了。所以异步IO需要有一个事件,当IO完成时会设置此事件,调用者在事件上等待。

 

31. 分别描述类CDatabase和类CRecordset的用途。

答:CDatabase类用于建立与数据源的连接,CRecordset类功能强大,可以将它看做数据源的一个记录集,其中封装了对记录集的各种操作,如:滚动,修改,增加,删除,查询等。

 

32. cdeclstdcallfastcall是什么?哪种可以实现个数不定的入口参数,为什么?

答:三者都是函数调用的约定。

  1. fastcall:采用寄存器传递参数,特点就是快了。
  2. cdeclcdeclare的缩写,是CC++程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,由调用者把参数弹出栈,对于传送参数的内存栈是由调用者来维护的,正因为如此,只有这种调用方式可实现个数不定的入口参数。
  3. stdcall:是Pascal程序的缺省调用方式,规则是,按从右至左的顺序压参数入栈,被调用的函数在返回前清理传送参数的内存栈。 上两者的主要区别是前者由调用者清理栈,后者由被调用的函清理栈。当然函数名的修饰部分也是不同的。

  

33. 如何查出内存泄漏和非法操作的BUG(在Release版本下)?

答:使用map文件。

 

34. 程序中的局部变量、全局变量和动态申请数据具体存在于什么位置?

   答:程序的局部变量存在于堆栈中,全局变量存在于静态区中,动态申请数据存在于堆中。

 

35. new delete malloc free的联系与区别?

答:new delete malloc free都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete会调用对象的destructor,而free不会调用对象的destructor

 

36. 描述内存分配方式以及它们的区别?

答:

  1. 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
  2. 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。
  3. 从堆上分配,亦称动态内存分配。程序在运行的时候用mallocnew 申请任意多少的内存,程序员自己负责在何时用freedelete释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。

 

37. 指针和引用有什么区别?

答:

  1. 引用在创建的同时必须初始化,即引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后面的任何地方重新赋值。
  2. 不存在NULL引用,引用必须与合法的存储单元关联;而指针则可以是NULL
  3. 引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是改变它和原始对象的绑定关系。
  4. 引用的创建和销毁并不会调用类的拷贝构造函数。
  5. 语言层面,引用的用法和对象一样;在二进制层面,引用一般都是通过指针来实现的,只不过编译器帮我们完成了转换。

 

38. 有一段文本,统计其中的单词数。例如:As a technology , "HailStorm"is so new that it is still only known by its code name.(注意:单词间的间隔不一定是一个空格。)

答:假设该文本已存入text这个数组里,可执行程序代码如下:

void main(){

   char text[1000]={"As a technology,'HailStorm'is so new that it is still only known by its code name."};

   int i=0,count=0;

   bool flag=true;

   while (text&&i<1000){

      if (text==' '){

           flag=true;

      }else if (flag==true && ((text>='a'&&text<='z')

      ||(text>='A'&&text<='Z'))){?

           count++;flag=false;

      }

      i++;

   }

   cout<<count;

}

  • 17
    点赞
  • 150
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值