C++学习笔记
Ref
- B站
Template
主要介绍...
这个关键字。
比如这里,可以接受个数随意,Type类型随意。比如这里7.5作为一个,其余的作为 ...
。然后可以这样递归。注意为了避免死循环,需要上面一个第一版本的print
处理边界条件(也即什么都不做)。
可以用sizeof
知道里面参数的个数。
当这两个并存的时候,谁会泛化?谁会特化?
举例了一种hash func的用法。对应了三种hash_val
函数版本的实现。可以看到只有第一版本合适,所以先调用1版本;在1版本里面给了seed然后继续调用自己hash_val
的一个特化版本(2版本);由于还是一包(…)所以还是调用自己。调用到终止的时候,调用版本3(也即边界处理)
一种tuple
用法。可以不断向上继承,并把第一个参数定义成变量。这样可以做出一个tuple。
一些标准库的改动
先前的C++需要空格,不然会报错。目前被改进了。
现在可以允许使用nullptr了
initializer_list
一致性初始化,可以都用{}做一致性初始化了。主要是看到{}便会初始化initializer_list并且分配给array。先打包成一个initializer_list然后再去匹配比如vector之类的实现。但是complex比较例外,会把array分解传给ctor(构造函数)。
比如这里,i就没有设置初值,但是j设置了。但是注意不能有窄化的转换,比如 x3的5.0转换不了5(int)。
举个例子,你可以这样调用会被自动识别成initializer_list(当然了,类型还是需要相同的)。关于处理,可以视为一个容器。
再举个例子,可以看到()
吻合版本1,后面传{}
的是initializer_list。注意你用s=
因为是新的对象,调用的是构造函数而不是运算符重载。注意如果没有版本2,因为q和s都是可以被拆解成两个所以仍然可以对应版本1。不过r会出问题,因为它被拆解成三个参数了。
关于源码的拆解,可以看到背后有_M_array(是迭代器?是array?)。还可以看到注释,当编译器看到{}
时候会调用构造函数进行构造private(也即传进array迭代器的头和长度并进行登记)。
关于array,这个是4.9的版本。不过比较复杂,一般看TR1就够了
TR1版本
可见,只传入头和长度,只有指针指向array。因此拷贝也只是浅拷贝(把指针拷贝过去,也即两个指针指向同一个array,比较危险)。
用处是比较广泛的。比如借助这个可以实现用max,min寻找{}里面(支持任意参数)的最大还有最小的数值。
explict
这样加入explict,使得接受一个以上的参数。可见,可以支持多个参数使得某些不成功。
先看一个参数的(因为这里im=0设置了默认值,所以仍然属于一个实参)。对于左边,+5被识别成+(5+0i)的复数形式然后用重载后的+。右边加上explicit
后,阻止了编译器的自动报错,只能指定后才能使用(这里就会找不到Complex和int的操作)。
range
for循环的新写法,可以把右边容器的元素一个一个拿到左边进行操作。这个elem是迭代器,可以用auto让它自己推断。另外,需要用&进行引用,也即直接指向并且修改(上面的只是拷贝和修改,开销也会更大)。注意,set,map类的关联性容器不支持改动容器里面的元素。
更底层的,也即用迭代器把容器里面的元素迭代出来进行操作。这里也可以认识到C++标准库也还有begin()
以及end
的全局函数可以支持容器的。
此外,本来可以从vs里面取出每个s然后进行C(s)。但是因为你有explicit,所以你不能把它转为C。因此真正报错的源头在explicit。
=default,=delete
自己指定构造函数后,编译器不会帮你用默认的构造函数(空的)。比如你写了Zoo(int,int)
,编译器就不会给你。Zoo(const Zoo&)
是拷贝构造函数。而Zoo(Zoo&&)
是右值引用。后面即为拷贝赋值和mov赋值。
delete主要用于这些特殊的函数。
可以看到,常规构造函数允许多个(你可以自己写一个然后再指定一个default的);copy构造函数不能重载,只能有一个,另外你写出来后也不能delete(写了为什么又要delete就会让编译器报错);
你也可以写一个func2=delete(表示你不想要这个函数了,虽然一般不这样写)。这五个特殊的函数也被称为Big-Five。
比如你对于空的class,C++也会自动补充这些函数来供使用。并且这些函数都是public并且inline的。
一个类只要有指针成员,几乎都可以断定需要自己写Big-Tree。相反的,只要没有,基本用默认的就行。比如Complex(复数没有指针,地址都是连续的)。但是你有指针的话(分为浅拷贝和深拷贝),需要写出那些复杂的拷贝(比如string)。
以复数为例,这里的初值会指定为对应类型的初值(比如int是0)。
STL概述
关于泛型编程。
STL的六个部件。把数据放在容器里面,然后算法又放在另一个算法里面。之后通过迭代器来进行处理。Adapter可以进行转换,有一些应用技巧。
比如这里,<>
里面是模板。分配器可以不写用默认的。count_if可以根据后面的条件在指定范围里面查找。less<>()
本来用于比较a和b的大小,现在可以用bind2nd
这个转换器绑定它的第二个参数为40(查找小于40的元素),not1
则是另一个转换器用于否定也即查找>=40的数。这一句也被称为predicate(判断式),这里会返回True或者False。
主要有序列性容器,关联性容器(其实无序容器底层应该也算关联性的)。