小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
1.new/delete和mallco/free的区别?
1> new/delete是C++的关键字,而malloc/free是库函数;
2> new操作符会根据类型自动计算大小,而malloc需要显示指定;
3> new操作符内存分配成功时,返回的是对象类型的指针,无须进行类型转换,而malloc返
回的是void*需要做强制类型转换;
4> new在申请空间时可以直接进行初始化,若不初始化,新申请的空间自动置0,而malloc
无法初始化,只能手动清零。
5> new类对象指针时,会调用构造函数,而malloc不会调用;
6> delete类对象指针时,会调用析构函数,而free不会调用;
2.浅拷贝和深拷贝有什么区别?
如果类中没有显式的给定拷贝构造函数和拷贝赋值函数,编译器会默认提供一个拷贝构造函数
和拷贝赋值函数,这两个函数就是浅拷贝,只完成成员间的简单赋值
对于没有指针成员的类,使用浅拷贝是没有问题的,但是如果类中有指针成员,必须显示的给
定拷贝构造函数和拷贝赋值函数,给新的指针分配新的空间,这种就是深拷贝。否则因为简单
的赋值,原类中的指针成员和新类中的指针成员指向的是同一块儿空间,在delete时,会出
现double free的问题。
3.一个空类会提供哪些默认成员函数,及各个函数的调用时机?
1> 无参构造函数:实例化对象时调用
2> 拷贝构造函数:用一个已经初始化的对象初始化新对象时调用
3> 拷贝赋值函数:两个已经初始化的对象进行赋值时调用
4> 析构函数:对象消亡时调用
4.重载(overload)和重写(overried)的区别?
1> 重载:是指允许定义多个同名函数,而这些函数的参数表不同:
(要求参数个数不同、或参数类型不同,或两者都不同)。
2> 重写:只发生在父子类之间,是指子类重新定义父类虚函数的方法。
(要求函数原型相同:名字、参数、返回值、const属性等都相同)。
5.析构函数设置成虚函数有什么用?
用于指引delete运算符,正确的释放空间,
如果基类的析构函数不是虚函数,在父类的的指针指向子类对象时,如果delete该指针,只
会调用父类的析构函数,不会调用子类的析构函数,此场景下,会存在内存泄漏的风险。
[重点难点]
掌握虚析构函数的作用,及不使用虚析构会造成异常的场景。
6.使用内联函数有什么要求?内联函数和带参宏的区别?
使用要求:
1> 建议编译器将内联函数在调用处展开,减少函数跳转的开销,使用内联函数要求,函数体
较小,逻辑比较单一;
2> 内联函数必须写在头文件.h里,不能写在源文件.cpp里;
内联函数与带参宏的区别:
内联函数是函数,与函数使用方法相同,而带参宏只是简单的替换。
#define MAX(a,b) (a)<(b)?(a):(b)
inline int find_min(int x, int y){
return x<y?x:y;
}
如上述两种方式在传的参数是i++时,会有区别。
[重点难点]
掌握内联函数特点,并能举例说明与带参宏的区别。
7.什么虚函数?什么是纯虚函数?什么是抽象类?
1> 虚函数:在基类中冠以关键字 virtual 的成员函数。 它提供了一种接口界面。允许在
派生类中对基类的虚函数重新定义。
2> 纯虚函数的作用:在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进
行定义。作为接口而存在 纯虚函数不具备函数的功能,一般不能直接被调用。且要求子类必
须重写。
3> 抽象类:类中至少有一个纯虚函数,那么这个类被称为抽象类。
抽象类中不仅包括纯虚函数,也可包括虚函数。抽象类必须用作派生其他类的基类,而不能用
于直接创建对象实例。但仍可使用指向抽象类的指针支持运行时多态性。
8.什么是多态,怎样实现多态?
多态:函数的多种表现形态。
实现多态:
1> 需要类的继承,多态发生在父子类之间;
2> 需要基类有虚函数或纯虚函数;
3> 子类需要重写父类的虚函数或纯虚函数;
4> 用父类的引用或指针指向子类的对象,可以调用子类的重写的父类的虚函数或纯虚函数;
9.什么是菱形/钻石继承,如何解决?
如果一个类有多个类共同派生,且这些父类又由公共的祖先基类派生,会导致在汇聚子类中访
问公共基类的成员时,会有歧义。
解决:需要在公共基类派生中间子类时加上关键字 virtual 修饰,这个virtual继承就是虚
继承。
对于虚继承来说,公共基类就叫做 虚基类。
虚基类中的成员由继承最末端的汇聚子类负责构造。
10.静态成员变量和静态成员函数在定义和使用时,有哪些注意事项?
1> 用static关键字声明成员变量或成员函数为 静态;
2> 静态成员变量必须初始化,且必须在类外全局处进行初始化;
3> 静态成员函数没有 this 指针,所以只能访问静态成员变量;
4> 使用静态成员可以让成员变量的访问或者函数逻辑的执行不依赖任何类对象。
11.常成员函数和常对象在定义和使用时有什么注意事项?
1> 声明和定义成员函数时候,加上 const 修饰,就是常成员函数;
2> 常成员函数只能对成员变量进行读值操作,不能修改成员变量的值;
3> 常成员函数可以重载 (常函数版本和非常函数版本可以构成重载关系);
4> 常对象:常对象只能调用常成员函数;
5> 非常对象:优先调用普通的成员函数,如果没有,调用常函数版本。
12.C++中的class和C语言中的struct的区别?(至少回答两点)
1> c++中的类默认的成员是私有的,struct默认的是共有的;
2> c++中的类可以定义成员函数,struct只能定义成员变量;
3> class继承默认是private继承,而struct继承默认是public继承;
4> class可以使用模板,而struct不能;
13.const修饰指针问题?下面语句的含义?
const int *p;
int const *p;
int * const p;
const int * const p;
const int *p; //指针指向的内容不可以通过指针修改
int const *p; //指针指向的内容不可以通过指针修改
int * const p; //指针的指向不能修改
const int * const p; //指针指向的内容和指针的指向都不能修改
14.简述面向对象的特征?
面向对象的主要特征是“封装、继承和多态”。
1> 封装:隐藏了实现细节,使得代码模块化;
2> 继承:派生类可以继承父类的数据和方法,扩展了已经存在的模块,实现了代码重用;
3> 多态:是“一个接口,多种实现”,通过派生类重写父类的虚函数,实现了接口的重用。
15.哪些函数不能被子类继承?
构造函数,析构函数,拷贝构造函数,拷贝赋值函数。
16.int id[sizeof(unsigned long)];这个对吗?为什么?
正确,sizeof是编译时运算符,编译时就确定了,可以看成和机器相关的常量。
17.请说出const与#define相比,有何优点?
1> const常量有数据类型,编译器可对其类型进行安全检查,可以避免一些低级的错误;
2> const可以节省空间,避免不必要的内存分配,提高效率。
因为#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若
干个备份;const定义的只读变量在程序运行过程中只有一份备份。
3> 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
18.请说出const与#define相比,有何优点?
1> const常量有数据类型,编译器可对其类型进行安全检查,可以避免一些低级的错误;
2> const可以节省空间,避免不必要的内存分配,提高效率。
因为#define只是进行展开,有多少地方使用,就替换多少次,它定义的宏常量在内存中有若
干个备份;const定义的只读变量在程序运行过程中只有一份备份。
3> 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
19.引用与指针有什么区别?
1> 引用必须初始化 指针可以不初始化
2> 引用不可以改变指向 指针可以
3> 不存在指向NULL的引用 指针可以指向NULL
4> 指针在使用前需要检查合法性 引用不需要
20.在什么时候需要使用“常引用”?
1> 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应
使用常引用。
2> 引用常量的时候。
21.将“引用”作为函数参数有哪些特点?
使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一
般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量
的副本;如果传递的是对象,还将调用拷贝构造函数。所以当参数传递的数据较大时,用引用
的效率和所占空间都好。
22.将“引用”作为函数返回值类型需要遵守的规则?
1> 不能返回局部变量的引用;
2> 返回函数内部new分配的内存的引用时,要有实际变量接,否则内存泄漏;
3> 可以返回类成员的引用,但最好是const;(函数里一般是某种业务规则的封装,需要保证完整性)
23.main函数执行以前,还会执行什么代码?
1> 初始化static静态和global全局变量,即data段的内容;
2> 将未初始化部分的全局变量赋初值:数值型short,int,long等为0,bool为FALSE,指
针为NULL,等等,即.bss段的内容;
3> 全局对象的构造函数;
4> 将main函数的参数,argc,argv等传递给main函数;
24.有哪几种情况只能用intialization list 而不能用assignment?
1> 类中有const成员变量时;
2> 类中的成员包含引用类型的成员;
3> 类中包含类类型(成员子对象)的成员时,必须使用初始化表的方式完成对类中类类型成
员中的成员变量的初始化
4> 需要调用父类构造函数时,只能在初始化表中调用;
25.分别写出BOOL,int,float,指针类型的变量a与“零”的比较语句?
BOOL:
if(a) or if(!a);
int:
if(0 == a);
float:
const float EXP = 0.000001;
if(a<EXP && a>-EXP);
pointer:
if(a != NULL) or if(a == NULL);
26.C++是不是类型安全的?
不是。因为两个不同类型指针之间可以强制转换(用reinterpret cast)。
解析:类型安全是指同一段内存在不同的地方,会被强制要求使用相同的办法来解释(内存中
的数据是用类型来解释的)。
C语言不是类型安全的,因为同一段内存可以用不同的数据类型来解释,比如1用int来解释就
是1,用boolean来解释就是true。
27.全局变量和局部变量有什么区别?是怎么实现的?操作系统和编译器是怎么知道的?
1> 生命周期不同:
全局变量随主程序创建和创建,随主程序销毁而销毁;局部变量在局部函数内部,甚至局部循
环体等内部存在,退出就不存在;
2> 作用域不同:
通过声明后全局变量程序的各个部分都可以用到;局部变量只能在局部使用;分配在栈区。
操作系统和编译器通过内存分配的位置来知道的,全局变量分配在全局数据段并且在程序开始
运行的时候被加载。局部变量则分配在堆栈里面。