C++面试知识点
一 C++程序基础
- C++可以通过
::
操作符来直接操作全局变量;
二 预处理、const、static与sizeof
#ifdef
、#else
、#endif
的使用- 利用
#define
实现宏求最大小值能产生比if else
更优化的代码 - 宏知识简单的文本替换,因此需要把参数很小心地括号括起来
- 使用
#define
进行宏定义的参数尽量不要用运算表达式代替,在生成程序的时候只是简单的文本替换,可能会得到与预期不一样的结果。
比如:#define SRQ(x) (x*x) ... int a,b; a = SQR(b+2);
编译器中会得到的是a=b+2*b+2;
生成的结果不一样。 - 宏参数的连接: 可以使用#把宏参数变成一个字符串,用##把两个字符串连接在一起。
- (用宏定义得到一个字符串的高位与低位
#define WORD_LD(xxx) ((byte)((word)(xxx))&255) #define WORD_LD(xxx) ((byte)((word)(xxx))>>8)
- 用宏定义得到一个数组所包含的元素个数
#define ARR_SIZE(a) (sizeof((a))/sizeof(a[0])))
- const定义的整型常量如果没有初始化,x就是一个随机数,并且以后也不能给它赋值了
- const 在指针左侧,表示const修饰的是指针所指向的内容,指针本身可修改;const在指针右侧,表示const修改的是指针本身,不允许修改。
- const与#define的特点与区别
#define
只是用来做文本替换的,编译器会把#define常量替换后续的字符穿然后编译, 生命周期止于编译器,存在于程序的代码段,在实际程序中知识一个常数,一个命令中的参数,没有实际的存在。
const常量存在于程序的数据段,并在堆栈分配了空间,const常量是一个Runtime的概念,在程序中可以被调用,传递。 const常量有数据类型
。而宏常量没有数据类型,编译器可以对const常量进行类型安全检查。 - C++中const的作用
const的作用主要有三个:1. 用于定义常量;2. 用于修饰函数形式参数,可以提高效率,(比如修饰引用)可以防止改变形参;3. 修饰函数的返回值。4. 修饰类的成员函数(函数定义体):任何不会修改数据成员的函数都应用const修饰。 - static的作用
C语言中,static有三个明显的作用:
(1)在函数体内,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变;
(2)在模块内,一个被声明为静态的变量,可以被模块内所有的函数访问,但不能被模块外其他函数访问,它是一个本地的全局变量;
(3)在模块内,一个被声明为静态的函数止咳被这一模块内的其他函数调用。 - static全局变量与普通的全局变量有什么区别?
(1)static全局变量与普通全局变量的区别是:static全局变量只初始化一次,防止在其他文件单元中被引用;
(2)static局部变量与普通的全局变量的区别是:static全局变量只被初始化一次,下一次依据上一次结果;
(3)static函数与普通函数的区别是:static函数在内存中只有一份,普通函数在每个被调用中位置一份复制品; - sizeof(p); 如果p是指针,在32位平台下会得到4; 如果p是数组,会返回数组的大小。
- 使用sizeof计算类的大小时需要注意字节对齐
- 使用sizeof()计算带有虚函数的类的大小时,虚函数会占用一个指针大小的内存,原因是系统多用了一个指针维护这个类的虚函数表,(这个虚函数无论有多少项,都不会再影响类的大小)。
- sizeof与strlen的区别如下
(1)sizeof是操作符,strlen是函数;
(2)sizeof操作付的结果类型是size_t,它在头文件中typedef
为unsignedint
类型,该类型保证能容纳实现所建立的最大对象的字节大小;
(3)sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以"\0"
结尾的;
(4)数组做sizeof
的参数不退化,传递给strlen
退化为指针;
(5)大部分编译程序在编译的时候sizeof就被计算过了,这就是sizeof(x)可以用来定义数组维数的原因。
(6)sizeof后如果是类型,必须加括弧;如果是变量名,可以不加括弧。这是因为sizeof
是个操作符,而不是个函数;
(7)在计算字符串数据的长度有区别;
(8)如果要计算字符串数组的长度,一定要用strlen; - sizeof的用途
(1)与存储分配和I/O系统那样的例程进行通信;
(2)查看某个类型的对象在内存中所占的单元字节;
(3)在动态分配一对象是,可能让系统知道分配多少内存;
(4)便于一些类型的扩充,在windows中很多结构类型就有一个专用的字段是用来放该类型的大小;
(5)由于操作数的字节数再是现实可能出现变化,建议在设计操作数字节大小事用sizeof来代替常量计算;
(6)如果操作数是函数中的数组形参或函数类型的形参,则sizeof给出其指针的大小; - 计算字符串长度的时候,应该用strlen(str)代替sizeof(str)/sizeof(str[0])。
- 使用sizeof计算联合体的大小时候,联合体的大小取决于它所有的成员中占用空间最大的一个成员的大小。
- 引入内联函数的主要目的是,用它替代C语言中表达式的宏定义来解决程序中函数调用的效率问题。
- 内联函数使用的场合,在C++类中应用最广,如果把这些函数成员函数定义成内联函数的话,将会获得比较好的小效率;
- 内联函数的缺点:内联是以代码膨胀(复制)为代价的,仅仅省去了函数调用的开销,从而提高函数的执行效率。以下情况不宜使用内联:
(1)如果函数体内代码较长,使用内联将导致内存消耗代价较高;
(2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大;
(3)另外,类的构造函数和析构函数容易让人误解为使用内联更加有效。要当心构造函数和析构函数隐藏一些行为,比如偷偷执行了基类或成员对象的构造函数和析构函数。 - 内联函数与宏的区别
(1)内联函数在编译时展开,宏在预编译时展开;
(2)在编译的时候,内联函数可以直接被镶嵌到目标代码中,宏只是一个简单的文本替换;
(3)内联函数可以完成诸如类型检测、语句是否正确等编译功能,而宏不具有这样的功能;
(4)宏不是函数,inline函数是函数;
(5)宏在定义是要小心处理宏参数,否则容易出现二义性。而内联函数定义是不会出现二义性;
三 引用和指针
引用时C++11引入的一个新特性,指针是C语言中广泛使用的数据类型,指针可以表示各种数据对象,例如简单变量、数组、结构体、类以及函数等。
引用类型的变量在声明的同时必须初始化,引用只能在声明的时候被赋值,以后都不能再把该引用名作为其他变量名的别名;
指针没有被初始化的时候是个野指针,对野指针的内容赋值可能会导致程序崩溃;
交换字符串可以使用引用来操作,利用传指针引用实现字符串交换
void(char *&x, char *&y) { char *temp; temp =x; x=y; y = temp; }
如果不使用引用,也可以使用二维指针来达到相同的效果
函数返回值类型后跟&表示返回的是返回值的引用
参数引用容易出错
引用和指针的区别
(1)初始化要求不同。引用在创建的同事必须出书常委,即引用到一个有效的对象;而指针在定义的时候不必初始化,可以在定义后的任何地方重新赋值;
(2)可修改性不同。引用一旦被初始化为指向一个对象。它就不能被改变为另一个对象的引用;而指针在任何时候都可以改变为指向另一个对象。给引用赋值并不是直接改变它和原始对象的绑定关系;
(3)不存在NULL引用,引用不能指向空值的引用,它必须总是指向某个对象;二指针可以是NULL,不需要总是指向某些对象,可以把指针指向任意的对象,所以指针更加灵活,也容易出错;
(4)测试需要的区别。由于引用不会指向空值,因此使用引用之前不需要测试它的合法性;而指针则需要经常进行测试。因此使用引用的代码效率比使用指针的要高。
(5)应用的区别。如果一旦指向某一个对象之后就不会改变指向,那么应该使用引用,如果有存在指向NULL(不指向任何对象)或在不同的时刻指向不同对象的这些可能性,应该使用指针。
总体来说,引用既具有指针的效率,又具有指针的方便性和直观性。为什么传引用比指针安全?
由于不存在空引用,并且引用一旦初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。
对于指针来说,它可以随时指向别的对象,并且可一不被初始化,或为NULL,所以不安全。const指针依然存在空指针,并且有可能产生野指针。解读复杂指针声明
使用右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该调转阅读方向。一旦解析玩圆括号力所有的东西,就跳出圆括号。重复这个过程,知道整个声明解析完毕。(修正:应该是先从未定义的标识符开始阅读,而不是从括号读起)。
例:int (*(*func)[5])(int *p);
func被一个圆括号包含,左边又有一个,那么func是一个指针;跳出括号,右边是一个[运算符号,说明func是一个指向数组的指针。现在往左看,左边有一个号,说明这个数组的元素是指针;再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是: func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*类型的形参,返回值为int类型的函数。
对指针进行加1操作,得到的是下一个元素的地址,而不是原有地址加1.所以一个类型为t的指针的移动,以
sizeof(t)
为移动单位。常量指针与指针常量的区别
常量指针就是指向常量的指针,它所指向地址的内容是不可修改的。
指针常量就是指针的常量,它是不可改变的指针,但是可以对它指向的内容进行修改。const位于号的左侧,则const是用来修饰指针所指向的常量, 如果const位于号的右侧,const就是修饰指针本身,即指针本身是常量。
六 C++面向对象
- struct与class有什么区别?
C语言中,strcut知识一种复杂数据结构类型定义,struct只能定义成员变量,不能定义成员函数,不能使用面向对象编程。
C++中,如果没有标明成员函数或者成员变量的访问权限级别,那么在struct中默认的是public,而class中默认的是private;