迭代器是一种检查容器内元素并遍历元素的数据类型。C++更趋向于使用迭代器而不是下标操作,因为标准库为每一种标准容器(如vector)定义了一种迭代器类型,而只用少数容器(如vector)支持下标操作访问容器元素。
共有五类迭代器:Input Iterator ,Output Iterator,Forwaed Iterator,Bidirectional Iterator,Random Access Iterator.
STL迭代器,是一个类模板,模拟了指针的功能,对很多指针常用的运算符进行了重载,封装了原生的指针,提供更高级的行为。返回的是对象的引用而不是值,需要解引用才可以输出。
虚函数是实现多态的一种方式。在多态中有函数重载的方法(编译器决定、静态多态),也有函数重写(运行期决定,动态多态),实现这种动态多态,就是依靠虚函数的方式,具体的说就是借助指针或者是引用,在基类中的函数必须有virtual关键字。我们使用基类的指针去指向派生类(子类对象),可以统一的用父类指针去表示各子类对象,只有当运行期间的时候,我们才知道使用的是哪个版本的函数,这就是虚函数的作用。
虚函数的实现方式是利用虚指针以及虚函数表来实现。(具体见继承篇:单继承、多继承、菱形继承)
虚表属于类,不属于具体的对象。一个类只有一份虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,
*__vptr
,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。
父类的析构函数设置为虚函数是为了防止内存泄漏,当我们使用父类的指针指向子类的对象时,希望释放基类指针的时候,可以释放掉子类的空间。
如果我们不设置父类的析构函数设置为虚函数,当父类指针指向子类时,释放父类指针,并不会调用子类的析构函数(在子类的析构函数中几乎不可避免的涉及到子类资源的释放,比如有一个指针指向了一块内存,不析构就内存泄漏了),只会调用基类的析构函数。
而不一定每一个类都有派生类都要被继承,所以默认构造并不是虚析构。
指针有一块自己的空间,本身就是一个对象,允许对指针去赋值和拷贝,指针也可以为空。
而引用是给对象起了一个别名,写成&d符号,引用必须要去初始化,之后会绑定在一起不可以修改,所以不可以为空。
他们的本质区别在于 指针指向一块内存,指针的内容就是内存的地址,而引用是某块内存的别名,无法改变指向
一些不同点:
vector是动态空间,size表示实际存储的数据数量,而capacity则是当前可容纳的数量,也就是开辟的内存。当vector动态增加时,一旦旧有的空间满了,就会以原来的capacity大小俩倍申请另一块空间,把内容拷贝过去,再增加新元素,最后把原空间释放。如果频繁的进行扩展,可以在一开始的时候提前声明用来开辟大容量。
无论释放(pop_back)、删除(erase)还是清空(clear),都只会改变size,不会改变capacity,只有vector析构才会清空内存。
map是关联容器,用键值对来存储,底层实现是红黑树,插入删除等,都可以再o(log n)时间内完成。
set底层也是红黑树,会自动调整二叉树结构。
关于红黑树见别的章节。
unordered_map是哈希表实现的,是无序的,时间复杂度是常数级别,但是空间复杂度很高,如果时间上要求高效率就用unoerdered_map,空间上敏感或者要求有序就用map
预编译其实就是在编译过程之前,进行的一些代码文本的替换工作。
#define
宏定义的替换#if
#endif
如果是0,就执行if后面的,否则就执行endif后面。显式构造函数。如果构造函数声明了这个关键字,就不允许隐式自动转换。
举个例子,有一个参数的的构造函数,如果声明了explicit,就不可以用A a = 1
这种方式构造,因为这其实就是一种隐式转换,把1当做参数去进行构造。
https://www.cnblogs.com/EvansPudding/p/12565968.html
https://www.cnblogs.com/EvansPudding/p/12566210.html
https://www.cnblogs.com/EvansPudding/p/12566403.html
原文:https://www.cnblogs.com/EvansPudding/p/12621250.html