前言一、基础篇
1.1 面向对象基本特征
封装继承多态
几种具体的表现
重写重载上转型(子类转父类) 二、高级篇
2.1 指针2.2 引用
左值引用c++ 11 特性:右值引用 三、拓展篇四、基础点
4.1 delete和free的异同
相同点区别点
1.delete会先调用析构再释放内存,free只会释放内存。 4.2 new和malloc的异同
相同点区别点
1. 申请的内存所在位置2.返回类型安全性3.内存分配失败时的返回值4.是否需要指定内存大小5.是否调用构造函数/析构函数6.对数组的处理7.new与malloc是否可以相互调用8.是否可以被重载9. 能够直观地重新分配内存10. 客户处理内存分配不足 4.3 野指针和内存泄漏
野指针内存泄漏
内存泄漏场景 4.3 构造函数
4.3.1 构造函数是否可以是虚函数——否4.3.2 构造/析构函数是否占据内存空间 4.4 静态链接和动态链接有什么区别?4.6 常见的拷贝
深拷贝和浅拷贝拷贝构造函数拷贝赋值操作符重载 4.7 字节对齐
字节对齐基本原则 五、重点
5.1 指针和引用的共同点和区别点
5.1.1 共同点
1. 指针和引用都可以作为形参,改变实参的值。 5.1.2 区别点
1.定义不同2、指针可以有多级,引用只能是一级3、指针可定义时不初始化,引用必须定义时初始化4、指针可以指向NULL,引用不可以为NULL5、指针初始化之后可以再改变,引用不可以6、sizeof 的运算结果不同7、自增运算意义不同8、指针和引用作为函数参数时,指针需要检查是否为空,引用不需要 5.2 main函数之前执行什么操作 六、难点
6.1 内存管理
6.1.1 RAII资源机制6.1.2 GC垃圾回收机制 七、工作建议
1.刚到新岗位,多沟通,不要闷声干。2.尽快熟悉,对自己明确的工作安排。 八、感谢以下链接作者的帮助
前言感谢以上作者的整理,以下内容都是结合了我自己的一些理解。
一、基础篇 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 引用 左值引用定义:变量的别名,初始化即定义。
左值引用在汇编层面其实和普通的指针是一样的
int a = 10; int &b = a; // 定义一个左值引用变量 b = 20; // 通过左值引用修改引用内存的值c++ 11 特性:右值引用
C++对于左值和右值没有标准定义,但是有一个被广泛认同的说法:
可以取地址的,有名字的,非临时的就是左值;不能取地址的,没有名字的,临时的就是右值;
不能取地址的,没有名字的,临时的就是右值
类型 && 引用名 = 右值表达式;
int &&var = 10;
三、拓展篇 四、基础点 4.1 delete和free的异同 相同点右值引用的存在并不是为了取代左值引用,而是充分利用右值(特别是临时对象)的构造来减少对象构造和析构操作以达到提高效率的目的。
都是释放内存
区别点 1.delete会先调用析构再释放内存,free只会释放内存。 4.2 new和malloc的异同new和malloc的异同
相同点 区别点 1. 申请的内存所在位置new:自由存储区(free store)上为对象动态分配内存空间,
malloc:从堆上动态分配内存。
自由存储区:C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。
堆:操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。
2.返回类型安全性自由存储区是否是堆:需要看new的实现,自由存储区不仅可以是堆,还可以是静态存储区,这都看operator new在哪里为对象分配内存。
3.内存分配失败时的返回值new返回标准类型指针。
malloc返回void*
4.是否需要指定内存大小new内存分配失败时,会抛出bac_alloc异常,它不会返回NULL;malloc分配内存失败时返回NULL。
5.是否调用构造函数/析构函数 6.对数组的处理使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算,而malloc则需要显式地指出所需内存的尺寸。
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)没有释放,导致运行时内存增加,直到一定程度导致程序崩溃。
内存泄漏场景malloc和free未成对出现;new/new []和delete/delete []未成对出现;
1>在堆中创建对象分配内存,但未显式释放内存;比如,通过局部分配的内存,未在调用者函数体内释放:
2>在构造函数中动态分配内存,但未在析构函数中正确释放内存;未定义拷贝构造函数或未重载赋值运算符,从而造成两次释放相同内存的做法;比如,类中包含指针成员变量,在未定义拷贝构造函数或未重载赋值运算符的情况下,编译器会调用默认的拷贝构造函数或赋值运算符,以逐个成员拷贝的方式来复制指针成员变量,使得两个对象包含指向同一内存空间的指针,那么在释放第一个对象时,析构函数释放该指针指向的内存空间,在释放第二个对象时,析构函数就会释放同一内存空间,这样的行为是错误的;没有将基类的析构函数定义为虚函数。
4.3 构造函数
4.3.1 构造函数是否可以是虚函数——否
4.4 静态链接和动态链接有什么区别?对象的大小是指在类实例化出的对象当中,他的数据成员所占据的内存大小,而不包括成员函数,所以不占用。
4.6 常见的拷贝 深拷贝和浅拷贝静态链接:是在编译链接时直接将需要的执行代码拷贝到调用处;
优点:在于程序在发布时不需要依赖库,可以独立执行,
缺点:在于程序的 体积会相对较大,而且如果静态库更新之后,所有可执行文件需要重新链接;动态链接:是在编译时不直接拷贝执行代码,而是通过记录一系列符号和参数,在程序运行或加载时将这些信息传递给操作系统,操作系统负责将需要的动态库加载到内存中,然后程序在运行到指定代码时,在共享执行内存中寻找已经加载的动态库可执行代码,实现运行时链接;
优点:在于多个程序可以共享同一个动态库,节省资源;
缺点:在于由于运行时加载,可能影响程序的前期执行性能。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享一块内存;深拷贝会创造一个相同的对象,新对象与原对象不共享内存,修改新对象不会影响原对象。 拷贝构造函数 拷贝赋值操作符重载 4.7 字节对齐 字节对齐基本原则
结构体内最大长度的变量为一次访问长度
五、重点 5.1 指针和引用的共同点和区别点 5.1.1 共同点 1. 指针和引用都可以作为形参,改变实参的值。举例
5.1.2 区别点 1.定义不同void function(Object *pObj)
等价于
void function(Object & obj)
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、指针和引用作为函数参数时,指针需要检查是否为空,引用不需要 5.2 main函数之前执行什么操作
1.设置栈指针;
2.初始化static静态和global全局变量,即data段的内容;
3.将未初始化部分的赋初值:数值型short,int,long等为0,bool为FALSE,指针为NULL;
4.将main函数的参数,argc,argv等传递给main函数,然后才真正运行main函数。
六、难点 6.1 内存管理 6.1.1 RAII资源机制 6.1.2 GC垃圾回收机制 七、工作建议 1.刚到新岗位,多沟通,不要闷声干。 2.尽快熟悉,对自己明确的工作安排。 八、感谢以下链接作者的帮助像Windows平台是根据编码格式Unicode或者多字节确定XXXCRTStartup函数再调用main
参考我的windows核心编程Main函数的生命周期
面向对象的三大基本特征,五大基本原则
指针和引用的区别
知乎 帅地 c++基础
知乎 拓跋阿秀 常遇见问题
C++动态内存分配与内存泄漏
new和malloc的异同


![[总结] C++ 面试 《一》基础篇 [总结] C++ 面试 《一》基础篇](http://www.mshxw.com/aiimages/31/703014.png)
