C++部分笔试面试题

C++部分笔试面试题

目录

C++部分笔试面试题

  • 列举并解释C++中的四种运算符转化,说明它们的不同点:
  • 什么是动态特性?
  • 对象在内存中是怎么存放的?
  • C++中const有什么作用?至少说明3种
  • C语言的volatile的含义是什么?使用时会对编译器有什么暗示?
  • 说下你对内存的了解?
  • 在什么时候需要使用“常引用”?
  • 全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?
  • 虚函数是怎么实现的?

列举并解释C++中的四种运算符转化,说明它们的不同点:

  • static_cast: 在功能上基本上与C风格的类型转换一样强大,含义也一样。它也有功能上限制。例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型或者把double类型转换成指针类型,另外,static_cast不能从表达式中去除const属性,因为另一个新的类型转换操作符const_cast有这样的功能。
  • const_cast: 用于类型转换掉表达式的const或volatileness属性。通过使用const_cast,你向人们和编译器强调你通过类型转换想做的只是改变一些东西的constness或者 volatileness属性。这个含义被编译器所约束。如果你试图使用const_cast来完成修改constness 或者volatileness属性之外的事情,你的类型转换将被拒绝。
  • dynamic_cast: 它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时)。
  • reinterpret_cast: 使用这个操作符的类型转换,其的转换结果几乎都是执行期定义(implementation-defined。因此,使用reinterpret_casts的代码很难移植。reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。

什么是动态特性?

  • 在绝大多数情况下,程序的功能是在编译的时候就确定下来的,我们称之为静态特性。
  • 反之,如果程序的功能是在运行时刻才能确定下来的,则称之为动态特性。
  • C++中,虚函数,抽象基类,动态绑定和多态构成了出色的动态特性。

对象在内存中是怎么存放的?

  • 在类对象的内存布局中,如果有虚函数,首先是该类的vtbl指针,然后才是对象数据,对象数据都是顺序存放,当然会涉及到字节对齐,这样会带来存取效率的提升。

C++中const有什么作用?至少说明3种

  • const用于定义常量:const定义的常量编译器可以对其进行数据静态类型安全检查。
  • const修饰函数形式参数:当输入参数为用户自定义类型和抽象数据类型时,将“值传递”改为“const&传递”可以提高效率。
  • const修饰函数的返回值:如果给“指针传递”的函数返回值加const,则返回值不能被直接修改,且该返回值只能被赋值给const修饰的同类型指针。
  • const修饰类的成员函数(函数定义体):任何不需要修改数据成员的函数都应该使用const修饰,这样即使不小心修改了数据成员或调用了非const成员函数,编译器也会报错。当const函数中使用到的变量被mutable修饰后,在const函数中可以对其进行修改。常函数只能调用类中的常函数,不能调用非常函数。

C语言的volatile的含义是什么?使用时会对编译器有什么暗示?

volatile的意思是易变的,也就是说,在程序运行过程中,有一些变量可能会被莫名其妙的改变,而优化器为了节约时间,有时候不会重读这个变量的真实值,而是去读在寄存器的备份,这样的话,这个变量的真实值反而被优化器给“优化”掉了,用时髦的词说就是被“和谐”了。如果使用了这个修饰词,就是通知编译器别犯懒,老老实实去重新读一遍!可能我说的太“通俗”了,那么我引用一下“大师”的标准解释: volatile的本意是“易变的”。由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

  • 1).并行设备的硬件寄存器(如:状态寄存器)
  • 2).一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
  • 3).多线程应用中被几个任务共享的变量嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难

说下你对内存的了解?

  • 1.栈 -由编译器自动分配释放
  • 2.堆 -一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
  • 3.全局区(静态区),全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束释放
  • 4.另外还有一个专门放常量的地方。-程序结束释放
  • 5程序代码区,存放2进制代码。
  • 在函数体中定义的变量通常是在栈上,用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上。在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。另外,函数中的"adgfdf"这样的字符串存放在常量区。

在什么时候需要使用“常引用”?

如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const类型标识符 &引用名=目标变量名;

 

将“引用”作为函数返回值类型的格式、好处和需要遵守的规则?

格式:类型标识符 &函数名(形参列表及类型说明){ //函数体 }

好处:在内存中不产生被返回值的副本;(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量生存期的结束,相应的引用也会失效,产生runtime error!

  • 注意事项:
  • (1)不能返回局部变量的引用。这条可以参照Effective C++[1]的Item 31。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
  • (2)不能返回函数内部new分配的内存的引用。这条可以参照Effective C++[1]的Item 31。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
  • (3)可以返回类成员的引用,但最好是const。这条原则可以参照Effective C++[1]的Item 30。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
  • (4)流操作符重载返回值申明为“引用”的作用:
  • 流操作符<<和>>,这两个操作符常常希望被连续使用,例如:cout << "hello" << endl;因此这两个操作符的返回值应该是一个仍然支持这两个操作符的流引用。可选的其它方案包括:返回一个流对象和返回一个流对象指针。但是对于返回一个流对象,程序必须重新(拷贝)构造一个新的流对象,也就是说,连续的两个<<操作符实际上是针对不同对象的!这无法让人接受。对于返回一个流指针则不能连续使用<<操作符。因此,返回一个流对象引用是惟一选择。这个唯一选择很关键,它说明了引用的重要性以及无可替代性,也许这就是C++语言中引入引用这个概念的原因吧。
  • 赋值操作符=。这个操作符象流操作符一样,是可以连续使用的,例如:x = j = 10;或者(x=10)=100;赋值操作符的返回值必须是一个左值,以便可以被继续赋值。因此引用成了这个操作符的惟一返回值选择。

全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?

  • 生命周期不同:
  • 全局变量随主程序创建和创建,随主程序销毁而销毁;局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在;
  • 使用方式不同:通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用;分配在栈区。
  • 操作系统和编译器通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面。
  • 与全局对象相比,使用静态数据成员有什么优势?
  • 主要有以下所述两种优势。
  • 静态数据成员没有进入程序的全局名字空间,因此不存在程序中其他全局名字冲突的问题。
  • 使用静态数据成员可以隐藏信息。因为静态成员可以是Private成员,而全局对象不能。

虚函数是怎么实现的?

  • 简单地说,虚函数是通过虚函数表实现的。事实上,如果一个类中含有虚函数,则系统会为这个类分配一个指针成员指向一张虚函数表(vtbl),表中每一项指向一个虚函数的地址,实现上就是一个函数指针的数组。

今天就介绍到这里

AC

 

你可能感兴趣的:(C++部分笔试面试题)