1、什么是引用,声明和使用引用要注意哪些问题? 引用就是某个目标变量的别名(alias),对引用的操作与对变量直接操作效果完全相同。声明一个引用的时候,切记要对其进行初始化。引用声明完毕后,相当于目标变量有两个名称,即该目标的原名称和引用名,不能再把该引用名作为其它变量名的别名。声明一个引用不是新定义一个变量,它只是表示该引用名是目标变量名的一个别名,它本身不是一种数据类型,因此引用本身不占用存储单元,系统也不给引用分配存储单元。不能建立数组的引用。
2、将引用作为函数的参数有哪些特点? (1)传递引用给函数与传递指针的效果是一样的。这时,被调函数被调函数的形参就成为原来主调函数的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参的操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;令一方面,在主调函数的调用点处,必须用变量的地址作为参数。而引用更容易使用,更清晰。
3、在什么时候需要使用“常引用”? 如果既要利用引用提高程序的效率,又要保护传递给函数的数据不在函数中被改变,就应使用常引用。常引用声明方式:const 类型标识符 &引用名=目标变量名;引用型参数应该在能被定义为const的情况下,尽量使用const。
将“引用”作为函数返回值类型的格式、好处和需要遵守的规则? 格式:类型标识符 &函数名(形参列表及类型说明){//函数体}; 好处:在内存中不产生被返回值的副本,(注意:正是因为这点原因,所以返回一个局部变量的引用是不可取的。因为随着该局部变量的生存周期的结束,相应的引用也会失效,产生runtime errir!) 注意事项:(1)不能返回局部变量的引用,主要是因为局部变量会在函数返回后被销毁,因此被返回的引用就成为了“无所指”的引用,程序会进入未知状态。(2)不能返回函数内部new分配的内存的引用,虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它局面,例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指的空间(由new分配)就无法释放,造成memory leak。(3)可以返回类成员的引用,但最好是const。主要原因是当对象的属性与某种业务规则相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完成性。
4、new,delete,malloc,free的关系? new会调用对象的构造函数,delete会调用对象的析构函数。malloc和free是C/C++语言的标准库函数,new与delete是C++的运算符,它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用malloc和free无法满足动态对象的要求,对象在创建的同时要自动执行构造函数,对象在销毁之前要自动执行析构函数。由于malloc和free是库函数而不是运算符,不在编译器控制权限之内,不能将执行构造函数和析构函数的任务强加于malloc和free。因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new和delete不是库函数。
5、delete与delete[]的区别? delete只会调用一次析构函数,而delete[]会调用每一个成员的析构函数。delete与new配套使用,delete[]与new[]配套。
6、面向对象的特点? 封装/继承/多态。在面向对象对象程序设计语言中,封装是利用可重用成分构造软件系统的特征,它不仅支持系统的可重用,而且有利于提高系统的可扩充性;消息传递可以实现发送一个通用的消息而调用不同的方法;封装是实现信息隐蔽的一种技术,其目的是使类的定义和实现分离。
7、子类析构时要调用父类的析构函数吗? 析构函数调用的次序是先派生类的析构后基类的析构,也就是说在在基类的析构调用的时候,派生类的信息已经全部销毁了。定义一个对象时,先调用基类的构造函数/然后调用派生类的构造函数,析构的时候恰恰相反:先调用派生类的析构函数,然后调用基类的析构函数。
8、C++中class和struct的区别? (1)默认继承权限,如果不明确指定,来自class的继承按照private继承处理,来自struct的继承按照public继承处理。(2)成员的默认访问权限,class的成员默认是private权限,struct默认是public权限。
引用与多态的关系? 引用是除指针外另一个可以产生多态效果的手段,这意味着,一个基类的引用可以指向它的派生类实例。
多态的作用? 1、隐藏实现细节,使得代码能够模块化;扩展代码块,实现代码重用。2、接口重用,为了类在继承和派生的时候,保证使用家族内任一类的实例的某一属性的正确调用。
9、描述内存分配的方式和它们的区别? 1、从静态存储区分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如全局变量,static变量。2、在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集。3、从堆上分配,亦称为动态内存分配。程序在运行时用malloc或new申请任意多少的内存,程序员自己负责在任何时候用free或delete释放内存。动态内存的生存周期有程序员决定,使用灵活,但问题多。
10、请说出const和#define相比,有何优点? const作用:定义常量、修饰函数参数、修饰函数返回值三个作用。被const修饰的东西受到强制保护,可以预防意外的改变,能提高程序的健壮性。1、const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查。2、有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。
11、简述数组与指针的区别? 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
12、类成员函数的重载、覆盖和隐藏的区别? a、成员函数被重载的特征:相同的范围(在同一个类中),函数名相同,参数不同,virtual关键字可有可无。b、覆盖是指派生类函数覆盖基类函数,特征是:不同的范围(分别位于派生类和基类),函数名字相同,参数相同,基类函数必须有virtual关键字。c、隐藏是指派生类的函数屏蔽了与其同名的基类函数,特征:如果派生类的函数与基类函数同名,但参数不同,此时不论有无virtual关键字,基类的函数将被隐藏;如果派生类的函数与基类的函数同名,并且参数相同,但是基类中没有virtual关键字,此时基类的函数被隐藏。
13、求出两个数中的较大值? ((a+b)+abs(a-b))/2
14、堆栈溢出一般是由什么原因导致的? 1、没有回收资源,2、层次太深的递归调用。
15、什么函数不能声明为虚函数? constructor
16、用两个栈实现一个队列的功能,给出算法和思路? 设两个栈为A和B,一开始均为空,将新元素push入栈A,判断栈B是否为空,如果不为空,则将栈A中的所有元素依次pop出并push到栈B,将栈B中的元素pop出。
17、定义一个标准宏MIN,这个宏输入两个参数并返回较小的一个? #define MIN(A,B) ((A)<=(B) ? (A) : (B))
交换两个数的宏定义? #define SWAP(a,b) (a)=(a)+(b);(b)=(a)-(b);(a)=(a)-(b);
18、关键字static的作用? 1、在函数体,一个被声明为静态的变量在这一函数被调用的过程中维持其值不变。2、在模块中(但在函数体外),一个被声明为静态的变量可以被模块中的所有函数访问,但不能被模块外的其它函数访问,它是一个本地全局变量。3、在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用,也就是,这个函数被限制在声明它的模块的本地范围内使用。
void foo(void){unsigned int a=6;int b=-20;(a+b > 6)puts(">6"):puts("<=6")}; 这个问题测试是否懂得C语言中自动转换规则,这个无符号整形问题的答案是输出">6" 。原因是当表达式中存在有符号类型和无符号类型时所有的操作数都自动转换为无符号类型。因此-20变成了一个正整数,所以表达式计算出的结果大于6.
19、如何打印出当前源文件的文件名以及源文件的当前行号? cout<<__FILE__; cout<<__LINE__; __FILE__和__LINE__是系统预定义宏,这种宏不是在某个文件中定义的,而是由编译器定义的。
20、引用与指针的区别是什么? 指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作,程序使用指针的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
21、结构和联合的区别? 1、结构和联合都是有多个不同的数据类型成员组成,但在任何同一时刻,联合中只存放了一个被选中的成员(所有的成员共用同一块地址空间),而结构的所有成员都存在(不同成员的存放地址不同)。2、对于联合的不同成员赋值,将会对其它成员重写,原来成员的值就不存在了,而对结构的不同成员赋值是互不影响的。
22、析构函数和虚函数的用法和作用? 析构函数是在对象生存期结束时自动调用的函数,用来释放在构造函数分配的内存;虚函数是指被关键字virtual说明的函数,作用是使用C++语言的多态性。
23、宏与内联函数的区别? 内联函数和宏都是在程序出现的地方展开,内联函数不是通过函数调用实现,是在调用该函数的程序处将它展开(在编译期间完成),宏同样是;不同的是:内联函数可以在编译期间完成诸如类型检测,语句是否正确等编译功能,宏就不具有这样的功能,而且宏展开的时间和内联函数也是不同的(在运行期间展开)
是不是一个父类写了一个virtual函数,如果子类覆盖它的函数不加virtual,也能实现多态? virtual修饰符会被隐形继承。private也被继承,只是派生类没有访问权限而已。virtual可加可不加。子类的空间里有父类的所有变量(static除外)。同一个函数只存在一个实体(inline除外)。子类覆盖它的函数不加virtual,也能实现多态。在子类的空间里,有父类的私有变量。私有变量不能直接访问。
24、多态,虚函数,纯虚函数的定义? 1、多态:是对于不同对象接收相同消息时产生不同的动作。C++的多态性具体体现在运行和编译两个方面:a、编译时多态性:通过重载函数和运算符的重载实现。b、运行时多态性:通过虚函数实现。 2、虚函数:在基类中冠以关键字virtual的成员函数。它提供了一种接口界面。允许在派生类中对基类的虚函数重新定义。也允许在基类中定义虚函数的实现。 3、纯虚函数:是在基类中声明的虚函数。他在基类中没有定义,但要求任何派生类都要定义自己的实现方法。在基类中实现纯虚函数的方法是在函数原型后面加“=0”,virtual void function()=0;纯虚函数的作用:在基类中为其派生类保留一个函数的名字,以便派生类根据需要对它进行定义。作为接口而存在,纯虚函数不具备函数的功能,一般不能直接调用。从基类继承来的纯虚函数,在派生类中仍是虚函数。如果一个类中至少有一个纯虚函数,那么这个类被称为抽象类(abstract class)。抽象类不仅包含纯虚函数,也包括虚函数。抽象类必须用作派生其他类的基类,而不能用于直接创建对象实例。但仍可使用指向抽象类的指针支持运行时多态性。
25、面向对象的三个基本特征,并简单叙述之? 1、封装:将客观事物抽象成类,每个类对自身的数据和方法实现保护protection(private,protected,public)2:继承:广义的继承有三种实现形式:实现继承(指使用基类的属性和方法而无需额外编码的能力)、可视继承(子窗体使用父窗体的外观和实现代码)、接口继承(仅使用属性和方法,实现滞后到子类实现)。前两种(类继承)和后一种(对象组合=>接口继承以及纯虚函数)构成了功能复用的两种形式。3:多态:是将父类对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
26、重载(overload)和重写(有的书也叫做“覆盖”)的区别? 1、从定义上来书:重载是指允许存在多个同名函数,而这些函数的参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)。重写直指子类重新定义父类虚函数的方法。2、重实现原理来说:重载:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的),对于重载函数的调用,在编译期间就已经确定了,是静态的,也就是说,它们的地址在编译期间就绑定了,因此,重载和多态无关。重写:和多态真正相关,当子类重新定义了父类的虚函数后,父类指针根据赋给它的不同的子类指针,动态的调用属于子类的该函数,这样的函数调用在编译期间无法确定的(调用的子类的虚函数的地址无法给出)。因此,这样的函数地址是在运行期绑定的。
27、多态的作用:1、隐藏实现细节,使得代码能够模块化,扩展代码模块,实现代码重用;2、接口重用,为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。
28、有哪几种情况只能用intialization list(初始化列表)而不能用assignment(赋值)? 当类中含有const、reference(引用)成员变量;基类的构造函数都需要初始化表。
29、C++是不是类型安全的? 不是,两个不同类型的指针之间可以强制转换(用reinterpret cast)。C#是类型安全的。
30、main函数执行以前,还会执行什么代码? 全局对象的构造函数会在main函数之前执行。
31、引用与指针有什么区别? 1、引用必须初始化,指针不必。2、引用初始化以后不能被改变,指针可以改变所指的对象。3、不存在指向空值的引用,但存在指向空值的指针。
32、写出float x与“零值”比较的if语句? if(x>0.000001 && x<-0.000001)
局部变量能否和全局变量重名? 能,局部变量会屏蔽全局变量,要使用全局变量,需要使用"::"。
33、如何引用一个已经定义过的全局变量? 可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变量,假定将那个变量写错了,那么在编译期间会报错,如果你用extern方式引用时,假定犯了同样的错误,那么在编译期间不会报错,而在链接期间报错。
34、全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么? 可以,在不同的C文件中以static形式来声明同名全局变量。可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错。
对于一个频繁使用的小函数,在C语言中应用什么实现,在C++中应用什么实现? c用宏定义,c++用inline
35、什么是编译器,何时需要预编译? 预编译又称为预处理,是做些代码文本的替换工作。处理#开头的指令,比如拷贝#include包含的文件代码,#define宏定义的替换,条件编译等,就是为编译做的预备工作阶段,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。
36、进程和线程的区别? 什么是进程(process),普通解释就是,进程是程序的一次执行,而什么是线程(thread),线程可以理解为进程中的执行的一段程序片段。在一个多任务环境下面的概念可以帮助我们理解两者之间的差别:进程是独立的,这表现在内存空间,上下文环境;线程运行在进程空间内。一般来讲进程是无法突破进程边界存取其他进程内的存储空间;而线程处于进程空间内,所以同一进程所产生的线程共享同一内存空间。同一进程中的两段代码不能够同时执行,除非引入线程。线程属于进程的,当进程退出时该进程所产生的线程都会被强制退出并清除。线程占用的资源要少于进程所占用的资源。进程和线程都可以有优先级。在线程系统中进程也是一个线程,可以将进程理解为一个程序的第一个线程。
阅读(1282) | 评论(0) | 转发(0) |