一.继承
子类对父类的访问
- public:保持原有权限
- private:全部变为私有权限
- protected:public 变为 protected 权限,protected 和 private不变
多继承导致的
- 命名冲突(加作用域符号)
- 菱形继承问题(使用虚继承)
存在相同基类时,导致最后的派生类内有两份基类;
原因:普通的继承中,最后的派生类对相同的基类会进行重复构造;
解决:最后的派生类对虚基类的构造函数调用,忽略其他派生类对虚基类的构造函数调用。
顺序:虚基类 基类1 基类2 最后的派生类
- 虚函数继承二义性(虚继承)
存在相同基类时,导致基类的两份虚函数表;
解决同上
二.多态
virtual
虚函数表:编译时确定,每个有虚函数的类都有一个虚函数表
虚指针:运行时创建对象确定;
- 不存在继承时,对象有一个虚指针指向自身的虚函数表。
- 单继承时:子类对象有一个虚指针指向自身的虚函数表,里面包含父类的虚函数地址、子类覆盖的虚函数地址、子类自己的虚函数地址。
- 多继承时:每一个有虚函数的父类,子类都有一个虚指针指向它的虚函数表;子类自己的虚函数地址存在第一个继承的父类的虚函数表中,后面的虚函数表存在偏移量。
三.STL
array(数组)
底层原理:将一段连续的内存空间按照元素类型的大小进行分割,并将每个元素存储在对应的内存块中。
优点:高效随机访问;连续内存分配,访问效率高;
缺点:大小固定;可能存在内存浪费;插入和删除效率低;
vector(动态数组)
优点:自动扩容无需指定大小;高效随机访问
缺点:自动扩容时进行整体的重新分配,拷贝和释放;内部插入和删除效率低
- 如何避免扩容:提前预估存储数量,使用 reserve 提前开辟
- 为什么扩容是1.5或者2倍:
- 顺序:开辟新空间、拷贝元素、释放旧空间。
- 理想状态:希望前面释放的空间再次使用;
- 2倍状态:每次扩容的空间都比前面释放的旧空间大,但是vector拷贝后可以自动调整为当前存储数量的最小值;
- 1.5倍状态:多次之后可以复用前面释放的旧空间。
- 超过2倍:浪费空间,调整浪费资源。
面试题:C++vector的动态扩容,为何是1.5倍或者是2倍_vector扩容-CSDN博客
list(双向链表)迭代
优点:高效插入和删除;器稳定;插入和删除不会失去空间;动态内存;
缺点:随机访问效率低;指针维护导致内存占用多;内存不连续,影响访问性能
stack(栈)
queue(队列)
unordered_map(无序哈希)
特点:平均查找效率为 O(1)
缺点:元素无序;占用空间比map大,且利用率不高;查询性能不太稳定,最坏达到O(n)
哈希表的实现可能会导致一些哈希冲突,从而需要更多的内存空间来存储数据。
另外,unordered_map 的哈希表需要根据实际数据量动态扩容,这也会导致一些额外的空间开销。
map(红黑树)
特点:有序;快速查找;插入、删除稳定性好
缺点:占用空间大;平均查询速度不如 unordered_map
红黑树的每一个节点都需要保存父节点位置、子节点位置和红/黑性质,所以占用空间大;
unordered_set(无序哈希)
特点:快速查找;高效的插入和删除
缺点:内存占用较大(哈希冲突);无序;
set(红黑树)
特点:自动排序;
缺点:
四.C++11
lambda
智能指针
auto
右值引用
inline
五.关键字
static
const