c++基础知识(容易面试到的)

构造函数与析构函数是否能为虚函数?

大家都知道析构函数可以是虚函数,构造函数不能为虚函数。为什么构造函数不能为虚函数呢?

1。存储空间角度
虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。
2。从使用角度
虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。
3。从作用
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。
4。
vtable
在构造函数调用后才建立,因而构造函数不可能成为虚函数。在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有必要成为虚函数。

malloc/free与new/delete的区别

简单点的:
malloc与free是C++/C 语言的标准库函数,new/delete 是C++的运算符
用malloc函数需要指定内存分配的字节数并且不能初始化对象,new会自动调用对象的构造函数。delete会调用对象的析构函数,而free不会调用对象的析构函数.
复杂的:
函数malloc 的原型如下:
void * malloc(size_t size); 用malloc 申请一块长度为length 的整数类型的内存,程序如下:
int *p = (int *) malloc(sizeof(int) * length); 我们应当把注意力集中在两个要素上:“类型转换”和“sizeof”。
1、malloc 返回值的类型是void *,所以在调用malloc 时要显式地进行类型转换,将void * 转换成所需要的指针类型。
2、malloc 函数本身并不识别要申请的内存是什么类型,它只关心内存的总字节数。
函数free 的原型如下:
void free( void * memblock ); 为什么free 函数不象malloc 函数那样复杂呢?这是因为指针p 的类型以及它所指的内存的容量事先都是知道的,语句free(p)能正确地释放内存。如果p 是NULL 指针,那么free对p 无论操作多少次都不会出问题。如果p 不是NULL 指针,那么free 对p连续操作两次就会导致程序运行错误。

运算符new 使用起来要比函数malloc 简单得多,例如:
int *p1 = (int *)malloc(sizeof(int) * length);  int *p2 = new int[length]; 这是因为new 内置了sizeof、类型转换和类型安全检查功能。对于非内部数据类型的对象而言,new 在创建动态对象的同时完成了初始化工作。如果对象有多个构造函数,那么new 的语句也可以有多种形式。
如果用new 创建对象数组,那么只能使用对象的无参数构造函数。例如
Obj *objects = new Obj[100]; // 创建100 个动态对象 不能写成
Obj *objects = new Obj[100](1);// 创建100 个动态对象的同时赋初值1 在用delete 释放对象数组时,留意不要丢了符号‘[]’。例如
delete []objects; // 正确的用法  delete objects; // 错误的用法 后者相当于delete objects[0],漏掉了另外99 个对象。
1 new自动计算需要分配的空间,而malloc需要手工计算字节数
2 new是类型安全的,而malloc不是,比如:
int* p = new float[2]; // 编译时指出错误  int* p = malloc(2*sizeof(float)); // 编译时无法指出错误 new operator 由两步构成,分别是 operator new 和 construct
3 operator new对应于malloc,但operator new可以重载,可以自定义内存分配策略,甚至不做内存分配,甚至分配到非内存设备上。而malloc无能为力
4 new将调用构造函数,而malloc不能;delete将调用析构函数,而free不能。
5 malloc/free要库文件支持,new/delete则不要。

vector map list set deque stack几大容器的使用区别

1。vector (连续的空间存储,可以使用[]操作符)快速的访问随机的元素,快速的在末尾插入元素,但是在序列中间岁间的插入,删除元素要慢,而且如果一开始分配的空间不够的话,有一个重新分配更大空间,然后拷贝的性能开销.
2。deque(小片的连续,小片间用链表相连,实际上内部有一个map的指针,因为知道类型,所以还是可以使用[],只是速度没有vector快)快速的访问随机的元素,快速的在开始和末尾插入元素,随机的插入,删除元素要慢,空间的重新分配要比vector快,重新分配空间后,原有的元素不需要拷贝。对deque的排序操作,可将deque先复制到vector,排序后在复制回deque。
3。list (每个元素间用链表相连)访问随机元素不如vector快,随机的插入元素比vector快,对每个元素分配空间,所以不存在空间不够,重新分配的情况
4。set 内部元素唯一,用一棵平衡树结构来存储,因此遍历的时候就排序了,查找也比较快的哦。
5。map 一对一的映射的结合,key不能重复。
6。stack 适配器,必须结合其他的容器使用,stl中默认的内部容器是deque。先进后出,只有一个出口,不允许遍历。
7。queue 是受限制的deque,内部容器一般使用list较简单。先进先出,不允许遍历。

下面是选择顺序容器类型的一些准则  

1.如果我们需要随机访问一个容器则vector要比list好得多 。

2.如果我们已知要存储元素的个数则vector 又是一个比list好的选择。  

3.如果我们需要的不只是在容器两端插入和删除元素则list显然要比vector好  

4.除非我们需要在容器首部插入和删除元素否则vector要比deque好。

5.如果只在容器的首部和尾部插入数据元素,则选择deque.

6.如果只需要在读取输入时在容器的中间位置插入元素,然后需要随机访问元素,则可考虑输入时将元素读入到一个List容器,接着对此容器重新排序,使其适合顺序访问,然后将排序后的list容器复制到一个vector容器中。


重载、覆盖和隐藏区别

a.成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual 关键字可有可无。
b.覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual 关键字。
c.“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)


将“引用”作为函数参数有哪些特点?

(1) 传递引用给函数与传递指针的效果是一样的。这时,被调函数的形参就成为原来主调函数中的实参变量或对象的一个别名来使用,所以在被调函数中对形参变量的操作就是对其相应的目标对象(在主调函数中)的操作。

(2)使用引用传递函数的参数,在内存中并没有产生实参的副本,它是直接对实参操作;而使用一般变量传递函数的参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量的副本;如果传递的是对象,还将调用拷贝构造函数。因此,当参数传递的数据较大时,用引用比用一般变量传递参数的效率和所占空间都好。

(3)使用指针作为函数的参数虽然也能达到与使用引用的效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"的形式进行运算,这很容易产生错误且程序的阅读性较差;另一方面,在主调函数的调用点处,必须用变量的地址作为实参。而引用更容易使用,更清晰。


虚函数的作用

虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,可以在基类的派生类中对虚函数重新定义,在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。


深拷贝和浅拷贝

在系统未显示定义拷贝构造函数的时候,都是用的浅拷贝,它完成成员的一一赋值。当数据成员中没有指针的时候,这样做是没有问题的。

但是当数据成员中有指针存在的时候,就会出现问题,这个时候我们采用深拷贝。深拷贝会在堆内存中申请新的空间来存放数据。


 

写出下列程序的运行结果

void Test( char p[20])

{

cout<<sizeof(p)<<endl;

}

int main()
{
 char *p="Hello!";
 char q[]="Hello!";

wchar_t s[]=L"Hello!";

char r[20];

 Test(r);
 cout<<sizeof(p)<<endl;
 cout<<sizeof(q)<<endl;

cout<<sizeof(s)<<endl;

return 0;

}


运行结果为:4 4 7 14

 

添加中。。。。。。。

你可能感兴趣的:(C++,面试,vector,list,delete,存储)