[总结] C++ 面试 《一》基础篇
前言
感谢以上作者的整理,以下内容都是结合了我自己的一些理解。
一、基础篇
1.1 面向对象基本特征
封装,继承,多态。
封装
定义:就是隐藏对象的属性和实现细节,仅对外公开接口(method),控制在程序中属性的读和修改的访问级别(public/protected/private)。
目的:封装的目的是增强安全性和简化编程,使用者不必了解具体的实现细节,而只是要通过外部接口,以特定的访问权限来使用类的成员。
继承
是面向对象的基本特征之一,继承机制允许创建分等级层次的类。
定义:继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
注意:C++支持多重继承(java只支持 单继承),可能会导致菱形继承。
多态
定义:多态同一个行为具有多个不同表现形式或形态的能力。是指一个类实例(对象)的相同方法在不同情形有不同表现形式。
(主要体现在重写和重载)
几种具体的表现
重写
子类继承父类后对父类方法进行重新定义。
重载
对已有方法的参数类型和数量的改变
上转型(子类转父类)
父类引用指向子类对象。
正确用法:
Parent* pParent = new Child;
Child child;
Parent* pParent = (Parent*)child;
错误用法
Child* pChild= new Parent;
二、高级篇
2.1 指针
指针定义:值为地址,指向内存。
2.2 引用
定义:变量的别名,初始化即定义。
三、拓展篇
四、基础点
4.1 delete和free的异同
相同点
都是释放内存
区别点
1.delete会先调用析构再释放内存,free只会释放内存。
4.2 new和malloc的异同
相同点
区别点
1. 申请的内存所在位置
new:*存储区(free store)上为对象动态分配内存空间,
malloc:从堆上动态分配内存。
*存储区:C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为*存储区。
堆:操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
*存储区是否是堆:需要看new的实现,*存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。
2.返回类型安全性
new返回标准类型指针。
malloc返回void*
3.内存分配失败时的返回值
new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
4.是否需要指定内存大小
使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
5.是否调用构造函数/析构函数
6.对数组的处理
C++提供了new[]与delete[]来专门处理数组类型:
A * ptr = new A[10];//分配10个A对象
使用new[]分配的内存必须使用delete[]进行释放:
delete [] ptr;
new对数组的支持体现在它会分别调用构造函数函数初始化每一个数组元素,释放对象时为每个对象调用析构函数。注意delete[]要与new[]配套使用,不然会找出数组对象部分释放的现象,造成内存泄漏。
至于malloc,它并知道你在这块内存上要放的数组还是啥别的东西,反正它就给你一块原始的内存,在给你个内存的地址就完事。所以如果要动态分配一个数组的内存,还需要我们手动自定数组的大小:
int * ptr = (int *) malloc( sizeof(int) );//分配一个10个int元素的数组
7.new与malloc是否可以相互调用
8.是否可以被重载
9. 能够直观地重新分配内存
10. 客户处理内存分配不足
4.3 野指针和内存泄漏
野指针
定义:指针指向未知内存,导致访问越界/非法访问等问题。
几种情况:
- 指针没初始化
- 指针指向的内存释放后,指针没置空
- 指针操作超越了变量的作用范围
内存泄漏
定义:堆区内存(new/malloc)没有释放,导致运行时内存增加,直到一定程度导致程序崩溃。
五、重点
5.1 指针和引用的共同点和区别点
5.1.1 共同点
1. 指针和引用都可以作为形参,改变实参的值。
举例
void function(Object *pObj)
等价于
void function(Object & obj)
5.1.2 区别点
1.定义不同
指针是一个变量,存储的是一个地址,指向内存的一个存储单元。
引用是原变量的一个别名,跟原来的变量实质上是同一个东西。
2、指针可以有多级,引用只能是一级
有意思的是:n级指针效果等于 n-1级指针+&
例如:
void Func(Object *** pppObj);
等价于
void Func(Object **& pprObj);
3、指针可定义时不初始化,引用必须定义时初始化
4、指针可以指向NULL,引用不可以为NULL
5、指针初始化之后可以再改变,引用不可以
6、sizeof 的运算结果不同
指针返回 指针大小;
引用返回原类型大小。
int a = 996;
int *p = &a;
int &r = a;
cout << sizeof(p); // 返回 int* 类型的大小
cout << sizeof(r); // 返回 int 类型的大小
7、自增运算意义不同
8、指针和引用作为函数参数时,指针需要检查是否为空,引用不需要
2.Main函数之前执行什么操作
1.设置栈指针;
2.初始化static静态和global全局变量,即data段的内容;
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL;
4.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数。
像Windows平台是根据编码格式Unicode或者多字节确定XXXCRTStartup函数再调用main
参考我的windows核心编程Main函数的生命周期
六、难点
6.1 内存管理
6.1.1 RAII资源机制
6.1.2 GC垃圾回收机制
七、工作建议
1.刚到新岗位,多沟通,不要闷声干。
2.尽快熟悉,对自己明确的工作安排。
八、感谢以下链接作者的帮助
面向对象的三大基本特征,五大基本原则
指针和引用的区别
知乎 帅地 c++基础
知乎 拓跋阿秀 常遇见问题
C++动态内存分配与内存泄漏
new和malloc的异同