21.请解释下面代码采用了何种C++特性(C语言不具备),作用是什么?
template<typename T>
T sum(T a, T b)
{
return (a + b);
}
表示函数模板,用于将一类功能相同,参数类型和返回值不同的函数抽象为一个模板,方便模板函 数调用。
22.请解释aaa.h中下面代码的功能
#if !defined(AFX_MYSUDU_H__9B952BEA_A051_4026_B4E5_0598A39D2DA4__INCLUDED_)
#define AFX_MYSUDU_H__9B952BEA_A051_4026_B4E5_0598A39D2DA4__INCLUDED_
... ...
#endif
这是预处理命令,可以保证多次包含此头文件时,只编译一次代码。
23. 请阅读下述代码,写出程序执行的结果
#include <iostream>
using namespace std;
class CBase
{
public:
virtual void print()
{
cout<< "base" << endl;
}
void DoPrint()
{
print();
}
};
class CChild1: public CBase
{
public:
virtual void print()
{
cout<< "child1" << endl;
}
};
class CChild2: public CBase
{
public:
virtual void print()
{
cout<< "child2" << endl;
}
};
void DoPrint(CBase *base)
{
base->DoPrint();
}
void main()
{
CBase* base = new CBase();
CChild1* child1 = new CChild1();
CChild2* child2 = new CChild2();
DoPrint(child1);
DoPrint(child2);
DoPrint(base);
delete base;
base = child1;
base->print();
delete child1;
delete child2;
}
child1
child2
base
child1(这是C++中类的虚函数实现多态的一个实例。)
24. CMemoryState 主要功能是什么?
用于检测内存泄露。 (分配了内存而没有释放,逐渐耗尽内存资源,导致系统崩溃。
内存泄露是指程序中间动态分配了内存,但是在程序结束时没有释放这部分内存,从而造成那一部 分内存不可用的情况,重起计算机可以解决,但是也有可能再次发生内存泄露,内存泄露和硬件没有关系,它是由软件引起的。
25. new delete和malloc free的区别与联系?
面试中可以这样回答:
都是在堆(heap)上进行动态的内存操作。用malloc函数需要指定内存分配的字节数并且不能初始化对象,new 会自动调用对象的构造函数。delete 会调用对象的析构函数,而free 不会调用对象的析构函数。
详细讲解:
① malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都用于在堆(heap)上进行动态的内存操作(申请动态内存和释放内存)。
② delete不仅会释放空间,在释放前会调用析构函数,和new对应,new调用构造函数,free只会释放内存。
③ 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象 在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
④ C++程序经常要调用C函数,其实new/delete内部实现也调用了malloc/free。
而C程序只能用malloc/free管理动态内存
⑤ new是强制类型的,不需要考虑类型,而malloc不是,它返回的指针是void*型,必须要强转成需要的类型。(注意)
⑥ new 可以调用构造函数在声明的时候初始化,malloc只是分配空间,需要在其他地方初始化。而且malloc需要指定分配空间大小, 而new是自动计算的。
⑦ new/delete是可以重载的,而重载之后,就成为了函数。当new/delete在类中被重载的时候,可以自定义申请过程,比如记录所申请内存的总长度,以及跟踪每个对象的指针。
⑧free和delete可以释放NULL指针。
举例说明:
Stu* stu = malloc(sizeof(Stu)); // Stu是一个类
采用malloc初始化,你将不会调用Stu的构造方法,而只是单纯的分配空间。而且我们只认为你是分配一个空间,而不是想创建一个对象。(用于struct)
Stu * stu = new Stu ();则会调用Stu的构造方法来初始化对象,也就是说你既要分配空间又要初始化这段空间,让它变成一个对象。(用于class)
delete与delete[]的区别
delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。当delete操作符用于数组时,它为每个数组元素调用析构函数, delete与new配套,delete []与new []配套。
提醒:关于new 、delete、malloc、free的区别,大家尽量多的记忆几点,面试的时侯可以多回答几点。
- C++中的class和struct的区别:
从语法上,在C++中(只讨论C++中)。class和struct做类型定义时只有两点区别:
① 默认继承权限:class的继承按照private继承处理,struct的继承按照public继承处理。
② 成员的默认访问权限:class的成员默认是private权限,struct默认是public权限。
C++和C中struct的区别:
在C++中struct可以定义方法,C中不可以。
- static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
原理分析:
① 全局变量(外部变量)的说明之前再冠以static 就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。 而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。
② 把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。
③ static函数与普通函数作用域不同。仅在本文件。只在当前源文件中使用的函数应该说明为内部函数(static),内部函数应该在当前源文件中说明和定义。对于可在当前源文件以外使用的函数,应该在一个头文件中说明,要使用这些函数的源文件要包含这个头文件
另外static函数与普通函数的一个区别是:static函数在内存中只有一份,普通函数在每个被调用中维持一份拷贝
简要回答:
① 限制变量的作用域(文件级的)。
② 设置变量的存储域(全局数据区)。
比对回答:
把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。static局部变量只被初始化一次,下一次依据上一次的结果值。
把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。static全局变量只初始化一次,防止在其他文件单元中被引用。普通全局变量在其他文件中也可用,需要用extern声明。
(根据问题倾向作答)
28. 局部变量能否和全局变量重名?
能,局部会屏蔽全局。要用全局变量,需要使用"::"。
29. 如何引用一个已经定义过的全局变量?
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定你将那个变量写错了,那么在编译期间会报错;如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。
30. 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?
可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
31. 关于const的考题
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样,a是一个常整型数。
第三个a是一个指向常整型数的指针(即,整型数是不可修改的,但指针可以)。
第四个a是一个指向整型数的常指针(即,指针指向的整型数是可以修改的,但指针是不可修改的)。
最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的,但是基本上不会应用这种形式)。
32. const与#define相比有何优点
① const 常量有数据类型,而宏常量没有数据类型。编译器可以对const修饰的数据进行类型安全检查。而对宏常量只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。
② 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
33. 几种内存分配方式以及它们的区别
① 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static 变量。
② 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令。
③ 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期由程序员决定,使用非常灵活,但问题也最多。
34. main函数执行以前还会执行什么代码?
全局对象的构造函数会在main函数之前执行。
35. C++是不是类型安全的语言?
不是,两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。
36. 结构体(struct)与联合(union)的区别:
① 结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在,而且不同成员的存放地址不同。
② 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。
(掌握结构中数据成员的对齐、补齐问题,及sizeof结构和联合的区别)
37. 实现多态的方法?
① 一个基类的引用可以指向它的派生类实例
② 一个基类的指针可以指向它的派生类实例
38. 重载(overload)和重写(overried,有的书也叫做“覆盖”)的区别?
① 重载:是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。
② 重写:是指子类重新定义父类虚函数的方法。
从实现原理上来说:
① 重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。对于这类函数的调用,在编译期间就已经确定了,是静态的。也就是说,它们的地址在编译期就绑定了(早绑定),因此,重载和多态无关!
② 重写:和多态真正相关。当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间是无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的(晚绑定)
39. 多态的作用?
主要是两个:
① 隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;
② 接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。
40. 有哪几种情况只能用初始化列表而不能使用赋值。
当类中含有const成员变量和引用成员变量时,基类的构造函数都需要初始化表。