1. 重写、重载和隐藏
重写
所谓重写,就是在继承中,子类重新定义父类的方法,这里需要注意的是:
- 必须在有继承关系的类中重写;
- 子类重写的方法名和参数列表必须与父类的方法名和参数列表一致;
- 父类方法用 virtual 修饰;
- 子类方法用 override 修饰;
- 重写一般用于接口实现和继承类的方法改写;
- 不管访问父类还是子类的方法,都是调用的子类的方法。
重载
所谓重载就是在同一个作用域中,存在多个名称相同但参数列表不同的方法,通过穿点不同的实参来决定具体调用哪个方法。这里有一点需要注意:返回值不同不能称为重载。同样我们来通过代码看一下重载:
隐藏
隐藏就比较有意思了,隐藏又称覆盖,父类方法中不做声明,子类方法中通过 new 关键字讲方法隐藏,但是他不会改变父类方法,也就是说:访问父类,调用父类方法,访问子类,调用子类方法。这个跟重写不同。我们在使用隐藏的时候需要注意以下几点:
- 隐藏的方法的标志必须要和被隐藏的方法的标志完全匹配;
- 隐藏的方法的返回值必须和被隐藏的方法的返回一致;
- 隐藏的方法所抛出的异常必须和被隐藏方法的所抛出的异常一致,或者是其子类;
- 被隐藏的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行隐藏。
2. 链表和数组有什么区别
- 存储形式:数组是一块连续的空间,声明时就要确定长度。链表是一块可不连续的动态空间, 长度可变,每
个结点要保存相邻结点指针。 - 数据查找:数组的线性查找速度快,查找操作直接使用偏移地址。链表需要按顺序检索结点, 效率低。
- 数据插入或删除:链表可以快速插入和删除结点,而数组则可能需要大量数据移动。
- 越界问题:链表不存在越界问题,数组有越界问题。
注 意 : 在 选 择 数 组 或 链 表 数 据 结 构 时 , 一 定 要 根 据 实 际 需 要 进 行 选 择 。 数 组 便 于 查 询 , 链 表 便 于 插 入 删 除 。 数 组 节 省 空 间 但 是 长 度 固 定 , 链 表 虽 然 变 长 但 是 占 了 更 多 的 存 储 空 间 。
3. vector的底层原理
首先创造一个容器vector a;,会生成三个指针,first,last,end。(last是不断移动的),初始化一个空的容器,三个指针均为空,因此capacity(end-first)和size(last-first)都为0。
(size是当前vector容器真实占用的大小,也就是容器当前拥有多少个元素。capacity是指预分配的内存空间。)
capacity==size,容器此时已满,若再要加入新的元素时,就要重新进行内存分配,进行内存扩充。
vector 容器扩容的过程需要经历以下 3 步:
- 完全弃用现有的内存空间,重新申请更大的内存空间;
- 将旧内存空间中的数据,按原有顺序移动到新的内存空间中;
- 最后将旧的内存空间释放。
因为所有的vector是顺序存储的,在后面push_back一个新的元素超过容器的capacity时,会开辟一个新的更大的内存空间(不一定是2倍),开辟多大的内存空间与windows,linux,编译器有关。开辟了新的连续的内存空间后,会将之前整体存放到新的内存空间中。
例如VS中,扩充是之前的百分之50(win)
在linux中,扩充是之前的2倍。
4. vector的reserve和resize
reserve
是直接扩充到已经确定的大小,可以减少多次开辟、释放空间的问题(优化push_back),就可以
提高效率,其次还可以减少多次要拷贝数据的问题。reserve只是保证vector中的空间大小(capacity)最少
达到参数所指定的大小n。reserve()
只有一个参数。
resize()
可以改变有效空间的大小,也有改变默认值的功能。capacity的大小也会随着改变。resize()
可以有
多个参数。
resize()
函数的作用是改变vector元素个数
resize(n,m)
第二个参数可以省略
n
代表改变元素个数为n,m
代表初始化为m
.
5.vector迭代器失效的情况
当插入一个元素到vector中,由于引起了内存重新分配,所以指向原内存的迭代器全部失效。
当删除容器中一个元素后,该迭代器所指向的元素已经被删除,那么也造成迭代器失效。erase方法会返回下
一个有效的迭代器,所以当我们要删除某个元素时,需要it=vec.erase(it)
;。