面试常见C++问题总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011366281/article/details/78253803

new 和malloc 的区别

   答:int *p;                                   

          p=new int;

          p=(int *)malloc(sizeof(int)*128);

1、new 是C++中的关键字,malloc是C语言中的函数;

2、new返回指定类型的指针,且可以自动计算所需大小;而malloc必须由我们指定字节数,且要强制转换数据类型;

3、new分配内存失败时,会抛出bac_alloc的异常;malloc分配失败时返回NULL;

4、new不只是分配内存,而且会调用类的构造函数,同理,delete也会调用类的析构函数;而malloc只分配内存,不会进行初始化类成员的工作,同样,free也不会调用析构函数;

5、new建立的是一个对象;malloc分配的是一块内存;

6、对于非内部数据类型的对象而言,只用malloc/free无法满足动态对象的要求,因为对象在创建的同时要自动助兴构造函数,对象在消亡之前要自动执行析构函数。malloc和free是库函数,不能把执行构造函数和析构函数的任务强加给malloc和free。因此,要完成一个动态内存分配和初始化工作要用到new和delete。见下面:

class Obj

{

public :

Obj(void){ cout << “Initialization” << endl; }

~Obj(void){ cout << “Destroy” << endl; }

void      Initialize(void){ cout << “Initialization” << endl; }

void      Destroy(void){ cout << “Destroy” << endl; }

};


void UseMallocFree(void)

{

Obj    *a = (obj *)malloc(sizeof(obj));     // 申请动态内存

a->Initialize();                          // 初始化

//…

a->Destroy();     // 清除工作

free(a);          // 释放内存

}


void UseNewDelete(void)

{

Obj    *a = new Obj;    // 申请动态内存并且初始化

//…

delete a;             // 清除并且释放内存

}

========================================================================

面向对象的三个特点

   继承、封装、多态

封装就是把客观事物封装成抽象的类,隐藏实现细节。在一个对象内部,某些代码或者是某些数据可以是私有的,不能被外界访问,通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或者是错误的使用可对象的私有部分。

继承是利用现有类的所有功能,在无需重新编写原来的类的情况下对这些功能进行扩展。

多态是一个接口,多种方法。在程序运行的过程中才决定调用的函数。分为静态多态和动态多态。静态多态通过函数重载实现,缺乏灵活性,动态多态是通过虚函数实现的。C++虚函数:在基类声明函数是虚拟的,并不是实际存在的函数,然后在派生类中才正式定义此函数。

虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。

虚函数的使用方法:

 在基类用virtual声明成员函数为虚函数,这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便调用。在类外定义虚函数时,不必再加virtual;


析构函数:

 析构函数的作用是在对象撤销之前做的必要的“清理现场”工作,当派生类的对象从内存中撤销时,一般先调用派生类的析构函数,再调用基类的析构函数。形式:~base(){}

 在C++中,构造函数用于在创建对象时进行初始化工作,不能声明为虚函数。因为在执行构造函数前对象尚未创建完成,虚函数表还不存在,也没有指向虚函数表的指针,所以此时无法查询虚函数表,也就不知道要调用哪一个构造函数。析构函数用于在销毁对象时完成相应的资源释放工作,可以被声明为虚函数。

虚析构函数:

 释放对象时如果只调用基类的析构函数,会导致派生类申请的空间得不到释放,除非程序运行结束被操作系统回收,否则就再也没有机会释放这些内存。这是典型的内存泄漏。例如:Base *p=new child; Base 是基类,child是派生类的对象,也就是基类的指针p指向了派生类对象,此时,如果p指针被撤销时,调用的是基类的析构函数,造成派生类的内存不会被释放,内存泄漏。为解决这个问题,需要将基类的析构函数声明为虚函数。这样,派生类的析构函数也会自动成为虚析构函数。当执行delete语句时,会先执行派生类的析构函数,再执行基类的析构函数,这样就不存在内存泄露了。

 通常来说,如果基类中存在一个指向动态分配内存的成员变量,并且基类的析构函数中定义了释放该动态分配内存的代码,那么就应该将基类的析构函数声明为虚函数。

========================================================================================

C和C++的区别:

C是一种结构化语言,重点在于算法和数据结构。C++是面向对象的语言,两者用于解决问题的思想方法不一样。

=========================================================================================

C++内存分配:

内存分为5个区:堆区、栈区、全局/静态存储区、代码区

堆区一般由程序员分配和释放,new分配的动态数据区放在堆中;

栈区由编译器自动分配和释放,存放函数的参数值,局部变量的值等;

由malloc等分配的内存块放在自由存储区中,他和堆是十分相似的,不过他是用free来结束自己的生命的。

全局/静态存储区中全局变量和静态变量都存放在全局数据区中。全局数据区的数据并不会因为函数的退出而释放空间。

常量存储区中存放的是常量,不允许修改。(当然,你要通过非正当手段也可以修改,而且方法很多。)

====================================================================================

虚函数和纯虚函数:

虚函数是为了重载和多态的需要,在基类中是有定义的,在子类中也可以不重载;纯虚函数在基类中是没有定义的,只是当做一个接口,必须在子类中加以实现。

=========================================================================================

六、虚函数表

   多态性可分为两类:静态多态和动态多态。函数重载和运算符重载实现的是静态多态,而动态多态是通过虚函数实现的。每个含有虚函数的类有一张虚函数表,表中每一项是一个虚函数的地址,也就是说,虚函数表的每一项是一个虚函数的指针。没有虚函数的C++类,是不会有虚函数表的。

七、C++中的空类默认产生的类成员函数

默认构造函数、拷贝构造函数、析构函数、赋值函数、取值运算



猜你喜欢

转载自blog.csdn.net/u011366281/article/details/78253803