考研复试专业课⾯试——C++
记:此篇博客是关于考研复试中专业课⾯试的相关知识点,按个⼈理解以及⽹上查资料来总结的,⽤来锻炼⾃⼰的逻辑思维,可能不太准确,希望指正。
1、什么是虚函数和纯虚函数?
基类指针可以指向其公有派⽣类对象,但当⽤基类指针访问其指向的派⽣类对象时只能访问该派⽣类从基类继承⽽来的对象⽽不能访问该派⽣类中定义的对象,此时就需要虚函数来解决这个问题。
虚函数是在基类中⽤virtual关键字说明并在派⽣类中被重新定义的成员函数,引⼊数函数的⽬的是为了动态绑定。引⼊纯虚函数的⽬的是为了派⽣接⼝,即在基类中为其派⽣类保留⼀个函数接⼝,以便于其派⽣类根据⾃⼰的需要进⾏重新定义。纯虚函数没有函数体,不具备函数功能,不能被调⽤。声明纯虚函数时令其等于0只是起到⼀个形式上的作⽤,并不代表其返回值为0,若⼀个类⾄少包含⼀个纯虚函数,则称该类为抽象类。
2、基类为什么要有虚析构函数?
如果没有虚析构函数,在销毁⼀个由基类指针指向的派⽣类对象时,只能调⽤基类的析构函数⽽不能调⽤派⽣类的析构函数,导致派⽣类对象所申请的空间⽆法释放⽽造成内存泄漏,此时就可以通过定义虚
析构函数,以便通过基类指针销毁派⽣类对象。
3、当i是⼀个整数时,i++和++i哪⼀个更快?他们的区别是什么?
当i是⼀个整数时,他们基本⼀样快。他们的区别在于:i++是先使⽤变量i,再使i的值加1,⽽++i是先使i的值加1,再使⽤i。也就是说
i++返回的是i的值,⽽++i返回的是i+1的值。
4、指针和引⽤的区别?
指针和引⽤的本质区别在于:指针是⼀个新的变量,只不过这个变量存储的是另⼀个变量的地址,可以通过该地址即指针变量来访问原来的变量,这种⽅式成为间接访问,需要⽤间接运算符*。引⽤只是另⼀个变量的别名,它和原本的变量拥有相同的地址,对引⽤的操作即是对该变量的操作,这种访问⽅式称为直接访问,不需要间接运算符,所以使⽤引⽤可以简化操作。
指针在做为函数参数时,内部是值传递,指针的值是不能改变的,要通过解引⽤才能够对原变量进⾏操作。引⽤在做函数参数时,内部传递的实际是变量的地址。
5、static关键字的作⽤?
修饰局部变量:局部变量本来存储在动态区,被static修饰后为静态变量,改变了其存储位置,存储在静态区。其⽣命周期与程序相同,在main函数之前初始化,在程序退出时销毁。
修饰全局变量:全局变量本来就存储在静态区,所以static修饰并不能改变其存储位置,但是可以改变其作⽤域,只有包含该变量定义的⽂件才能访问。
修饰函数:static修饰函数作⽤也是改变其作⽤域,⾄于包含该函数定义的⽂件才能调⽤。对于静态函数来说,其声明和定义应该在同⼀个⽂件中。
修饰成员变量:static修饰的类成员变量是类的全局变量,被该类的所有对象所共有,包括派⽣类对象,即所有的对象都只维持同⼀个实例。所以static修饰的成员变量要在类外进⾏初始化,⽽不能在类内初始化。
修饰成员函数:static修饰的成员函数是该类所有对象所共享的函数,使这个类只存在这⼀个函数,没有this指针且被static修饰的成员函数只能访问static成员变量。静态成员可以独⽴访问,即不必创建对象即可进⾏访问。
当同时编译多个⽂件时,⾮static的全局变量或函数都是具有全局可见性的,也可以被其他的源⽂件来访问。对于函数来讲,static修饰只是起到了限制其作⽤域的作⽤。
6、为什么static和const不能同时修饰成员函数?
c++编译器在实现const的成员函数时为了使其不改变类的实例的状态,就添加了参数const this*,但当声明⼀个static成员函数时是不存在this指针的,也就是⼆者的⽤法是相冲突的。
7、const的作⽤?
const可以⽤来定义变量使其为只读变量,不能做修该,使⽤const修饰的变量⼀定要进⾏初始化。const还可修饰函数的参数或返回值。
const成员函数:也就是在成员函数的参数列表后⾯添加const关键字,const成员函数可以访问const的成员变量和⾮const的成员变量,但是不能修改任何变量。因此,在声明成员函数时,如果该函数不对数据成员做修改操作,则可能把其声明为const成员函数。
const对象只能访问const成员函数不能访问⾮const成员函数,⾮const对象可以访问任意成员函数,包括const成员函数。
8、C++的多态性?
多态性可以简单的概括为“⼀个接⼝,多种⽅法”,分为编译时多态性和运⾏时多态性,编译时多态性通
过重载函数(重载)实现,运⾏时多态性通过虚函数(重写)实现。重载要求函数名相同但函数的参数列表不相同,重写要求函数名,函数类型,函数参数列表都相同。
多态和⾮多态的区别就是函数地址是早绑定还是晚绑定。如果函数调⽤在编译时就能确定函数的调⽤地址则是静态的,即函数地址是早绑定,若函数调⽤在编译时不能确定函数的调⽤地址需要在运⾏时才能确定则是动态的,即函数地址是晚绑定。
常见的⽤法是声明基类的指针,⽤该指针指向派⽣类对象,调⽤相应的虚函数,根据指针指向的派⽣类对象的不同⽽实现不同的⽅法。
9、⾯向对象和⾯向过程的区别?
⾯向过程:是分析出解决问题的步骤,然后⽤函数⼀步⼀步实现这些步骤,在使⽤时就依次调⽤函数。优点是:⽐⾯向对象的性能⾼,因为类需要实例化,开销⽐较⼤,⽐较消耗资源,缺点是:没有⾯向对象易扩展,易维护,易复⽤。static修饰的变量
⾯向对象:是把要解决的问题划分成各个对象,建⽴对象的⽬的是为了描述某个事物在整个问题解决步骤中的⾏为。优点是:易维护,易复⽤,易扩展,因为⾯向对象具有封装、继承和多态性,可以设计出低耦合的系统,使系统更加灵活,易于维护。缺点是:性能较低。
10、C和C++的区别?
C语⾔是⾯向过程的语⾔,是结构化的语⾔,考虑如何通过⼀个过程对输⼊进⾏处理得到输出。C++是⾯向对象的语⾔,考虑如何根据具体问题域建⽴⼀个合适的对象模型,具有“封装、继承和多态”的特性。封装隐藏了实现细节,使代码模块化;派⽣类继承⽗类的⽅法和数据,扩展原有的模块,实现了代码的复⽤;多态性是“⼀个接⼝,多个⽅法”,通过派⽣类重写⽗类的虚函数,实现接⼝的复⽤。
c语⾔⽤malloc和free动态管理内存,不⽀持函数重载,没有引⽤;c++⽤new和delete动态管理内存,⽀持函数重载,有引⽤的概念。
11、虚函数表是针对类的还是针对对象的?同⼀个类的两个对象的虚函数表是怎么维护的?
编译器为⼀个类维护⼀个虚函数表,每个对象的⾸地址保存着该虚函数表的指针,同⼀个类的不同对象指向同⼀张虚函数表。在类内部添加⼀个指向该虚函数表的指针,该虚函数表保存所有对象的虚函数⼊⼝地址,可以根据此虚函数表到⾃⼰的函数的⼊⼝,每个类的虚函数表都不⼀样。对于纯虚函数来说,相当于⼀个占位符,纯虚函数在虚函数表中占⼀个位置,当派⽣类实现后再把真正的函数指针填进去。
12、内联函数和宏定义的区别?const和#define的区别?
宏定义是在预编译时把所有的宏名⽤宏体来替换,简单来说就是字符串的替换。内联函数是在编译时进⾏代码插⼊,在调⽤内联函数的地⽅直接把内联函数的内容展开,省去了函数调⽤时的压栈和出栈操作,提⾼了效率。内联函数是嵌⼊代码,在调⽤函数时不进⾏跳转⽽是把内联函数的代码插⼊到相应位置。内联函数在编译时要进⾏参数类型检查,因此内联函数更安全、可靠,但这是牺牲空间来换取的性能提升。
const是在编译时替换,define是在预处理的时候替换;define没有类型,不进⾏类型检查,const有类型,要进⾏类型检查。
13、堆和栈的区别?
管理⽅式:栈是由编译器⾃动管理⽽堆需要⼿动释放。
增长⽅向:栈向下增长,以降序分配存储空间;堆是向上增长,以升序分配存储空间
是否产⽣碎⽚:进栈和出栈都是按照顺序依次进⾏的,不会产⽣碎⽚;堆要频繁的进⾏new和delete,造成存储空间不连续,易产⽣碎⽚。
分配⽅式:栈能够进⾏动态分配也能静态分配;堆只能进⾏动态分配。
分配效率:栈是系统提供的数据结构,计算机在底层对其进⾏⽀持,进栈和出栈都有专门的指令;堆是由c或c++函数库提供的,且机制⽐较复杂,栈的效率⽐堆的效率要⾼,但是却没有堆灵活。
14、c++中类与结构体的区别?
最⼤的区别就是默认访问控制,struct作为数据结构的实现体,其默认的数据访问控制为public,class作为类的实现体,其默认的成员访问控制为private的。并且class可以⽤于定义模板参数,类似于typename,⽽struct则不能定义模板参数。
15、析构函数的作⽤?
析构函数⽤于释放定义的对象的指针,默认的析构函数不是显⽰调⽤的,⾃定义的析构函数要进⾏显⽰调⽤。
当类⾥⾯只⽤到了基本数据类型,如int double等时,系统的默认析构函数不进⾏任何操作;当⽤到如vector和string等数据类型时,会⾃⼰调⽤系统默认的析构函数。
如果是⾃定义的析构函数,且占⽤了内存空间等资源时,在程序结束时需要调⽤⾃定义的析构函数来释放掉占⽤的资源,防⽌内存泄漏。
16、操作系统和编译器如何区分全局变量和局部变量?
操作系统只管进程调度,编译器根据变量存储空间的分配位置来判断,全局变量分配在全局数据段(静态存储区)并在程序运⾏前加载,局部变量分配在(动态存储区)栈中。
17、结构体和联合体的区别?
结构体和联合体都是由不同类型的数据成员所构成的,联合体中在某⼀个时间点只能有⼀个变量成员存在,所有的变量成员共享⼀段内存空间,对联合体不同成员赋值时会对其他成员进⾏重写,其他成员的值就不存在了。结构体中在某⼀个时间点所有变量成员均存在,且所有变量的内存地址不同,对结构体的成员赋值时是不会产⽣相互影响的。
18、重载和重写的区别?
从定义上来说:重载时允许存在多个同名函数,但这些函数的参数表不同(可能是参数个数不同,可能是参数类型不同,可能两者都不相同),重写是⼦类对⽗类中的虚函数重新定义。
从实现原理上来说:重载时编译器根据函数不同的参数表,对函数的名称进⾏处理,使这些同名函数成为不同的函数。重写是当⼦类对⽗类虚函数进⾏重新定义后,⽗类指针根据赋给其不同的⼦类指针,动态的调⽤该⼦类的函数,在编译时不能确定调⽤的是哪个函数。
19、有关纯虚函数的理解?
纯虚函数是为你的程序制定的⼀种标准,它只是⼀个接⼝,需要在⼦类中进⾏实现,且纯虚函数没有函数体,不具备函数功能,不能被调⽤。包含纯虚函数的类为抽象类,这种类不能直接⽣成对象,需要在⼦类中重写虚函数之后才能够使⽤。
虚函数是为了继承接⼝和默认⾏为,实现动态绑定。纯虚函数只是为了继承接⼝,⾏为必须重新定义。
20、内存溢出、内存泄漏的原因?
内存溢出是指在申请内存空间时出现没有⾜够的内存空间供其使⽤的情况,内存溢出的原因⼤致有如下4种:
(1) 内存中加载的数据量过于庞⼤,例如⼀次从数据库中取较多的数据
(2) 代码中出现死循环或者循环产⽣过多重复的对象实体
(3) 递归调⽤的层次太深导致堆栈溢出
(4) 内存泄漏导致内存溢出
内存泄漏是指在向系统申请了内存空间等资源,在使⽤完毕后没有进⾏资源释放,⽽造成占⽤有效内存。
21、为什么要声明虚基类?
在当基类被多个⼦类继承时,在这些继承路径的汇合处基类会产⽣多个实例,从⽽导致⼆义性。如果想要这个基类只产⽣⼀个实例供所有⼦类共享使⽤,则要⽤virtual关键字把该公共基类声明为虚基类。
22、c++⽂件编译与执⾏的四个阶段?
(1)根据⽂件中的预处理指令来修改源⽂件
(2)编译成汇编代码
(3)将汇编代码翻译成机器指令
(4)链接⽬标代码⽣成可执⾏程序
23、定义和声明的区别?
变量声明:⽤于告诉程序变量的类型和名字
变量定义:为变量分配内存空间,还可以为变量赋初值,变量有且只有⼀个定义。在变量定义的同时也是声明了变量的类型和名字。
extern关键字:⽤extern关键字是声明变量⽽不是定义变量。
24、c++内存分配的⽅式?
(1)在静态存储区分配内存,编译时分配,在程序运⾏的整个期间都存在
(2)在栈中分配内存,系统⾃动进⾏分配和释放,例如局部变量就是在栈中分配内存空间
(3)在堆中分配内存,需要程序员⼿动进⾏分配和释放,并指定⼤⼩。
栈可以进⾏动态分配和静态分配,⽽堆只能够进⾏动态分配,栈的效率⽐堆的⾼但没有堆灵活。
25、继承体系下同名成员函数的关系?
(1)重载:在同⼀作⽤域,函数名相同,参数列表不同,返回值类型可以相同也可以不相同
(2)重写:在不同的作⽤域(分别在⽗类和⼦类),函数名相同,参数列表相同,返回值类型相同,基类的函数需要有virtual关键字声明。
(3)重定义:在不同的作⽤域(分别在⽗类和⼦类),函数名相同,在⽗类和派⽣类中只要不符合重写的均是重定义
26、什么情况下会调⽤拷贝构造函数(三种情况)?
类会⾃动⽣成构造函数:普通构造函数和拷贝构造函数,当⽣成⼀个普通的类对象的时候会⾃动调⽤普通构造函数,当⽤⼀个类对象去初始化另⼀个对象时会调⽤拷贝构造函数;
调⽤拷贝构造函数的三种情况:
(1)当⽤⼀个类的对象去初始化另⼀个新的对象时
(2)当函数的参数为类的对象且为值传递的时候,当为引⽤时不会调⽤
(3)当函数的返回值为类的对象或者引⽤的时候
27、虚函数是怎么实现的?
每⼀个含有虚函数的类都有⼀个虚函数表,虚函数表中保存着该类的所有虚函数的函数指针(地址),类的实例对象不包含虚函数表,只有虚函数指针。
c++到此就更新完毕了~

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。