c++
###指针和引用的区别
1. 指针是一个变量,存储了指向数据的地址;引用只不过是原变量的别名,实质上跟原变量是一回事
2. 指针可以多级,引用只能有一级
3. 指针可以为NULL,引用不能为空,创建时就必须初始化
4. 指针可以用const,但是引用没有const //应该改为指针可以有两层const,引用只有一层
5. 指针的值初始化后可以改变,引用的值不可以改变
6. sizeof引用得到变量的大小,sizeof指针得到指针本身的大小
7. 指针和应用的自增++运算意义不一样
###指针、引用
1. 引用必须被初始化;引用并非对象,没有地址空间,所以没有指向引用的指针。
2. 离变量名最近的符号对变量的类型有最直接的影响,如int * &a; a为引用,是int指针的引用;
3. 常量指针:即指向常量的指针,指针本身可以改变,但指向的对象不可改变。int const * p; 或 const int * p;
4. 指针常量:即指针本身是个常量,指针本身不可改变,指向的对象可以改变。int * const p;
5. 指向常量的指针常量:即指针本身是常量,不可改变,指向的对象也不可改变。const int * const p;
###string、vector
1. 列表初始值还是元素数量,依赖于传递初始值时使用的时花括号还是圆括号。
2. 不能在范围for循环或使用了迭代器的循环中向vector添加元素。
3. 任何一种可能改变vector对象容量的操作,如push_back,都会使该vector的迭代器失效
4. 两个vector相等当且仅当他们所含的元素个数相同,且对应位置的元素值也相同。
5. vector可以用下标运算符访问已存在的元素,而不能用于添加元素,添加元素用push_back。
1. 在函数内部使用static使局部变量的生命周期贯穿函数调用及之后的时间,作用域不变。
2. 实参初始化形参时会忽略掉顶层const,传递给形参的是否是const类型的都可以
3. 数组有两个性质:不允许拷贝数组和使用数组时通常会将其转化为指针。因此给函数传递数组时,实际上传递的是数组首元素的指针。
4. 函数重载不依赖于返回值。由函数名和参数共同决定使用哪个函数,与返回值无关。如果返回值不同,其他元素都相同,则是错误。
5. 一个拥有顶层const的形参无法和一个没有顶层const的形参区分开来,不能重载。
6. 但如果形参是指针或者引用,可以用const重载,此时的const是底层的。实参为const则必须用const版本的函数,而不是const则优先选择非const的版本。
7. 在函数声明中指定默认实参,放在头文件中就可以了,以后的函数定义不需要在写默认实参。
8. 内联函数可避免函数调用的开销,内联函数定义要放在头文件中。
###IO流
1. IO对象不可拷贝,只能使用引用来用于函数的返回值和形参
2. 文件结尾:s.eof(); 可恢复错误:s.fail(); 系统级错误:s.bad(); 表示流处于有效状态:s.good();处于有效状态。cin.clear()清除错误标志位,
3. 换行刷新缓冲区endl;直接刷新缓冲区flush;插入空字符后刷新缓冲区ends;
4. 每次都刷新缓冲区操作符unitbuf,回复正常使用nounitbuf。如cout << unitbuf表示立即刷新
5. 流自己清空缓冲区:cin.ignore()
6. C++的IO流效率比较低,面向对象导致的,而且输入输出时采用虚函数,更增加开销。
1. 定义在类内的函数且没有加inline是隐式的内联函数
2. this指针是一个指针常量,总是指向自己,不能被改变
3. 当提供一个类内初始化值的时候,必须用符号=或者花括号表示
4. 返回*this,如果返回对象本身的引用,则可以通过一串语句进行操作对象;返回非引用则传递副本,无法达到此效果。
5. 基于const的重载:可以给成员函数重载两个函数const版本和非const版本,让编译器找合适的
6. 定义小函数的好处:避免多处使用相同代码;我们预期这些小函数以后会变得很复杂,这样修改会很方便;添加和删除调试信息只需要在一处;小定义成内联函数不会带来任何额外开销。
7. 类之间的友元关系:定义一个友元类,则友元类的成员函数可以访问此类的所有成员。
8. 友元关系不存在传递性,每个类负责控制自己的友元类或友元函数
9. 声明友元函数的作用域和友元函数本身声明的作用域是由区别的,必须以自身的声明作用域为准
10. 如果使用const、引用或者某种未提供默认构造函数的类类型,应通过构造函数初始列表提供初值
11. 一方面初始化和赋值在底层效率有区别,另一方面更重要的是一些成员必须初始化。应养成使用构造函数初始值的习惯。
12. 初始化列表的顺序与类内变量的声明顺序有关,与初始化列表的顺序无关。最好令构造函数初始值的顺序与成员声明的顺序保持一致
###static的用法
####面向过程程序设计中的static
#####1.静态全局变量
在全局区分配内存、自动初始化为0、在声明它的文件之外不可见。
#####2.静态局部变量
在全局区分配内存、自动初始化为0、生命周期从声明到程序结束,但其作用域是在声明它的函数内。也就是次静态局部变量只有此函数可以使用,相当于此函数专用的全局变量。
#####3.静态函数
在函数名前加static定义静态函数,只能在声明它的文件中使用。
####面向对象的static
#####静态数据成员:在类内数据成员的声明前加static,即声明类内静态数据成员。
1. 非静态成员每个对象都有自己的拷贝。而静态数据成员在程序中只有一份拷贝,由该类的所有对象共享。但其不属于特定的类,在没有任何类实例时就可以操纵它。
2. 存储在全局数据区。由于定义时要分配空间,所以不能在类声明中初始化。在类外初始化,初始化时不需要再加static关键字。格式为:<数据类型> <类名>::<静态数据名> = <值>
3. 虽然同样遵循public、protected、private的访问权限,但不能在类外被访问。访问静态成员有两种格式:<类对象名>.<静态成员名>;如果静态成员为public,可以<类名>::<静态数据名>
4. 静态数据成员主要用在各个对象都有相同的某项属性时。一是可以节省存储空间,二是在需要修改时,只需要修改一处即可。比如存款类中的利息。
5. 同全局变量相比,静态数据成员有两个好处。一是没有进入程序的全局命名空间,不会和其他全局变量造成冲突;二是可以实现信息隐藏,可以定义为private,而全局变量不能。
#####静态成员函数
与静态数据成员类似,静态成员函数不是为类中某个具体的对象服务,是为类的全部服务。
1. 普通成员函数内部缺省的隐藏了指向对象本身的this指针,而静态成员函数没有this指针。因此它不能访问类对象的非静态数据成员和非静态成员函数,只能调用静态成员函数。
2. 静态成员之间可以互相访问,包括静态数据成员和静态成员函数。
3. 由于没有this指针的额外开销,其速度与类的全局函数相比有少许提升。
4. 类的对象可以用.或->直接调用静态成员函数,也可以在没有类对象时访问:<类名>::<成员函数名>(<参数表>)
###顺序容器:vector、deque、list、forward_list 、array、string
提供了控制元素存储和访问顺序的能力。此顺序不依赖于元素的值,而是与元素加入容器时的位置相对应。
####优缺点
1. string和vector:随机访问速度快,但是插入和删除非常耗时;
2. list(双向链表)和forward_list(单向链表):插入和删除数据速度快,但是不支持随机访问,且内存开销较大。
3. deque(双端队列):支持随机访问,两端插入和删除元素速度快,但在中间插入和删除速度慢
4. 如果有更好的理由选择其他容器,否则应使用vector。(使用list也比较通用)
####操作
1. insert将元素插入到迭代器所指定位置之前,c.insert(p, t)在p所指之前插入t。同样也可以在指针后插入范围元素,也可以利用insert的返回值在同一位置反复插入元素。
2. list、forward_list、deque中又push_front操作,可以向表头插入元素
3. swap操作交换两个相同类型容器的内容。swap(a, b)或a.swap(b).除array外,swap不对任何元素进行拷贝、删除或插入操作,可以在常数时间内完成,且除String外,指向容器的指针、引用和迭代器都不会失效,只是扔指向交换前的那些元素。array的swap操作会真正交换元素。
4. 成员访问:at和[]只适用于string、vector、deque和array,使用at如果越界,会抛出out_of_range异常,back不适用forward_list。front、back等操作都返回的时引用。对一个空容器调用front和back,就像使用越界下标一样,是严重错误。
5. erase操作和插入操作类似,删除元素函数并不检查参数,需自己确定他们是存在的。同样可能导致迭代器失效。
6. 初始化:只有顺序容器的构造函数才接受大小参数,关联容器并不支持;可以用迭代器范围给标准容器初始化。C c(b, e)用b和e之间的元素初始化c。
7. 改变容器大小和管理容量:resize(n)改变容器大小,若改变的值小于size()会丢弃n后的元素;reserve(n)改变容器的容量,若小于n则什么也不做;capacity()返回当前的容量大小。
#####额外的string操作
string中的函数均由多个重载版本,根据实际情况选择合适的函数版本使用。
1. substr(pos, n)取字串操作;append()在末尾追加;replace()替换操作相当于先erase后insert;find()函数查找字串在主串中的位置,可逆向查找;compare()类似于c语言中的strcmp函数。
2. 数值转化函数:to_string();将数值转化为string,val可以是任何算数类型。还有其他一系列将String转化为数值的函数。
####迭代器
1. 迭代器的概念是标准库的基础
2. 迭代器使用左闭右开的区间,即begin指向第一个元素,end指向最后一个元素的下一位置。这样的编程假定可以放心的使用++begin来达到end。
3. 赋值相关运算会导致左边容器内部的迭代器、引用和指针失效。(swap操作不会)
4. 对于向迭代器添加元素、从迭代器中删除元素、resize、赋值、swapd等都可能会导致迭代器失效,因此必须保证每次改变容器的操作之后都正确的重新定位迭代器。对于vector、string和deque尤为重要。
5. 不要缓存.end()的值,end()的操作很快。
####适配器Adaptor:stack、queue、priority_queue
本质上,一个适配器是一种机制,能使某种事物看起来像另外一种事物。
###关联容器associative-container:map、set
关联容器的元素是按关键字来保存和访问的。
1. 传递给sort()函数的可调用对象必须满足跟关联容器中关键字一样的需求;
2. 严格弱序列(strict weak ordering):两个关键字不能同时小于等于对方;如果K1小于等于k2,且k2小于等于k3,那k1必须小于等于k3;如果两个关键字,任何一个都不小于等于对方,则是相等。
3. set中的元素是const的,map中的元素是pair,pair中的第一个元素是const,所以关联容器可用于只读取元素的算法。但是关联容器自己的算法比调用泛型好用的多。
4. map的insert()操作的返回值是一个pair,pair.first为指向给定关键字的迭代器,pair.second为bool值,表示是否插入成功。
5. map的下标操作符可能会插入一个新元素,只能对非const的map使用下标或at操作。at()操作若关键字不存在,则抛出out_of_range异常。且与string和vector不同,下标操作符的返回类型与迭代器解引用的类型不同。下标运算符返回mapped_type,解引用迭代器返回value_type