1、只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为复制构造函数。与默认构造函数一样,复制构造函数可由编译器隐式调用。复制构造函数可用于:
根据另一个同类型的对象显示或隐式初始化一个对象。
复制一个对象,将它作为实参传给一个函数。
从函数返回时复制一个对象。
初始化顺序容器中的元素。
根据元素初始化列表初始化数组元素。
1、只有单个形参,而且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为复制构造函数。与默认构造函数一样,复制构造函数可由编译器隐式调用。复制构造函数可用于:
根据另一个同类型的对象显示或隐式初始化一个对象。
复制一个对象,将它作为实参传给一个函数。
从函数返回时复制一个对象。
初始化顺序容器中的元素。
根据元素初始化列表初始化数组元素。
1、类定义了一个新的类型和一个新的作用域。
每个类可以没有成员,也可以定义多个成员,成员可以是数据、函数或类型别名。
2、在类内部定义的函数默认为inline。像其他inline一样,inline成员函数的定义必须在调用该函数的每个源文件中是可见的。不在类定义体内定义的inline成员函数,其定义通常应放在有类定义的同一头文件中。
3、将关键字const加在形参列表之后,就可以将成员函数声明为常量:
double avg_price() const;
const成员不能改变其所操作的对象的数据成员。const必须同时出现在声明和定义中,若只出现在其中一处,就会出现一个编译时错误。
4、一个访问标号(private、protected、public)可以出现的次数通常是没有限制的。每个访问标号指定了随后的成员定义的访问级别。这个指定的访问级别持续有效,直至遇到下一个访问标号或看到类定义体的右花括号为止。
5、除了定义数据和函数成员之外,类还可以定义自己的局部类型名字。
class Screen {
public:
typedef std::string::size_type index;
private:
index cursor;
};
6、在声明之后、定义之前,类类型是一个不完全类型,即已知是类类型,但不知道包含哪些成员。
不完全类型只能以有限方式使用。不能定义该类型的对象。不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数。
7、不能从const成员函数返回指向类对象的普通引用(只能返回const引用)。const成员函数只能返回*this作为一个const引用。
基于成员函数是否为const,可以重载一个成员函数;同样地,基于一个指针形参是否指向const,可以重载一个函数。
8、类的数据成员声明为mutable即可在任何成员函数内(甚至在const成员函数内)进行修改。
可变数据成员永远都不能为const,甚至当它是const对象的成员时也如此。因此,const成员函数可以改变mutable成员。要将数据成员声明为可变的,必须将关键字mutable放在成员声明之前:mutable size_t access_ctr;
9、完全限定名之后的类成员函数定义、形参表和函数体都处于类作用域中。
在定义于类外部的成员函数中,形参表和成员函数体都出现在成员名之后。这些都是在类作用域中定义,所以可以不用限定而引用其他成员。
与形参类型相比,返回类型出现在成员名字前面。如果函数在类定义体之外定义,则用于返回类型的名字在类作用域之外。如果返回类型使用由类定义的类型,则必须使用完全限定名。
10、构造函数初始化式只在构造函数的定义中而不是声明中指定。不管成员是否在构造函数初始化列表中显示初始化,类类型的数据成员总是在初始化阶段初始化。初始化发生在计算阶段开始之前。
有些成员必须在构造函数初始化列表中进行初始化。对于这样的成员,在构造函数体中对它们赋值不起作用。没有默认构造函数的类类型的成员,以及const或引用类型的成员,不管是哪种类型,都必须在构造函数初始化列表中进行初始化。
记住,可以初始化const对象或引用类型的对象,但不能对它们赋值。初始化const或引用类型数据成员的唯一机会是在构造函数初始化列表中。
必须对任何const或引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式。
11、构造函数初始化列表仅指定用于初始化成员的值,并不指定这些初始化执行的次序。成员被初始化的次序就是定义成员的次序。第一个成员首先被初始化,然后是第二个,依次类推。
12、可以用单个实参来调用的构造函数定义了从形参类型到该类类型的一个隐式转换。
通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为explicit。将构造函数设置为explicit可以避免错误,并且当转换有用时,用户可以显式地构造对象。explicit关键字只能用于类内部的构造函数声明上。
13、友元声明可以出现在类中的任何地方:友元不是授予友元关系的那个类的成员,所以它们不受其声明出现部分的访问控制影响。
友元可以是普通的非成员函数,或前面定义的其他类的成员函数,或整个类。将一个类设为友元,友元类的所有成员函数都可以访问授予友元关系的那个类的非公有成员。
友元类,必须先定义该类。友元函数,必须先定义授予友元关系的类。
14、因为static成员不是任何对象的组成部分,所以static成员函数不能被声明为const。毕竟,将成员函数声明为const就是承诺不会修改该函数所属的对象。最后,static成员函数也不能被声明为虚函数。
static数据成员必须在类定义体的外部定义(正好一次)。
不像普通数据成员,static成员不是通过类构造函数进行初始化,而是应该在定义时进行初始化。
保证对象正好定义一次的最好办法,就是将static数据成员的定义放在包含类的非内联成员函数定义的文件中。
const static数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体在外进行定义。在类内部提供初始化式时,成员的定义不必再指定初始值。
static数据成员的类型可以是该成员所属的类类型。
占位符。
1、关联容器通过键存储和读取元素,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。
2、map的元素以键-值对的形式组织:键用作元素在map中的索引,而值则表示所存储和读取的数据。set仅包含一个键,并有效地支持关于某个键是否存在的查询。
3、map 关联数组;元素通过键来存储和读取
set 大小可变的集合,支持通过键实现的快速读取
multimap 支持同一个键多次出现的map类型
multiset 支持同一个键多次出现的set类型
4、pair类型提供的操作
pair<T1, T2> p1; 创建一个空的pair对象,它的两个元素分别是T1和T2类型,采用值初始化
pair<T1, T2> p1(v1, v2); 创建一个pair对象,它的两个元素分别是T1和T2类型,其中first成员初始化为v1,而second成员初始化为v2
make_pair(v1, v2) 以v1和v2值创建一个新的pair对象,其元素类型分别是v1和v2的类型
p1 < p2 两个pair对象之间的小于运算,其定义遵循字典次序:如果p1.first < p2.first 或者!(p2.first < p1.first) && p1.second < p2.second,则返回true
p1 == p2 如果两个pair对象的first和second成员依次相等,则这两个对象相等。该运算使用其元素的==操作符
p.first 返回p中名为first的(公有)数据成员
p.second 返回p中名为second的(公有)数据成员
5、在使用关联容器时,它的键不但有一个类型,而且还有一个相关的比较函数。默认情况下,标准库使用键类型定义的<操作符来实现键的比较。
6、map对象的元素是键-值对,也即每个元素包含两个部分:键以及由键关联的值。map的value_type就反映了这个事实,它是存储元素的键以及值的pair类型,而且键为const。例如,word_count数组的value_type为pair<const string, int>类型。
在学习map的接口时,需谨记value_type是pair类型,它的值成员可以修改,但键成员不能修改。
7、map类定义的类型
map<K, V>::key_type 在map容器中,用做索引的键的类型
map<K, V>::mapped_type 在map容器中,键所关联的值的类型
map<K, V>::value_type 一个pair类型,它的first元素具有const map<K, V>::key_type类型,而second元素则为map<K, V>::mapped_type类型
8、使用下标访问map与使用下标访问数组或vector的行为截然不同:用下标访问不存在的元素符号将导致在map容器中添加一个新的元素,它的键即为该下标值。
9、map容器提供的insert操作
m.insert(e) e是一个用在m上的value_type类型的值。如果键(e.first)不在m中,则插入一个值为e.second的新元素;如果该键在m中已存在,则保持m不变。该函数返回一个pair类对象,包含指向键为e.first的元素的map迭代器,以及一个bool类型的对象,表示是否插入了该元素
m.insert(beg, end) beg和end是标记元素范围的迭代器,其中的元素必须为m.value_type类型的键-值对。对于该范围内的所有元素,如果它的键在m中不存在,则将该键及其关联的值插入到m。返回void类型
m.insert(iter, e) e是一个用在m上的value_type类型的值。如果键(e.first)不在m中,则创建新元素,并以迭代器iter为七点搜索新元素存储的位置。返回一个迭代器,指向m中具有给定键的元素
10、不修改map对象的查询操作
m.count(k) 返回m中k的出现次数
m.find(k) 如果m容器中存在按k索引的元素,则返回指向该元素的迭代器。如果不存在,则返回超出末端迭代器
11、返回迭代器的关联容器操作
m.lower_bound(k) 返回一个迭代器,指向键不小于k的第一个元素
m.upper_bound(k) 返回一个迭代器,指向键大于k的第一个元素
m.equal_range(k) 返回一个迭代器的pair对象。它的first成员等价于m.lower_bound(k)。而second成员则等价于m.upper_bound(k)
1、容器的容器vector< vector<string> > lines;必须用空格隔开两个相邻的>符号,以示这是两个分开的符号,否则,系统会认为>>是单个符号,为右移操作符,并结果导致编译时错误。
2、使用迭代器编写程序时,必须留意哪些操作会使迭代器失效。使用无效迭代器将会导致严重的运行时错误。
3、容器定义的类型别名:
size_type 无符号整型,足以存储此容器类型的最大可能容器长度
iterator 此容器类型的迭代器
const_iterator 元素的只读迭代器类型
reverse_iterator 按逆序寻址元素的迭代器
const_reverse_iterator 元素的只读(不能写)逆序迭代器
difference_type 足够存储两个迭代器差值的有符号整型,可为负数
value_type 元素类型
reference 元素的左值类型,是value_type&的同义词
const_referenct 元素的常量左值类型,等效于const value_type&
4、在顺序容器中添加元素:
push_back
push_front 只适用于list和deque容器类型
insert
5、访问元素:
c.back()
c.front()
c[n] 只适用于vector和deque容器
c.at(n) 只适用于vector和deque容器
6、删除元素:
erase
clear
pop_back
pop_front 只适用于list或deque容器
7、顺序容器的赋值操作:
c1 = c2 删除容器c1的所有元素,然后将c2的元素复制给c1。c1和c2的类型(包括容器类型和元素类型)必须相同
c1.swap(c2) 交换内容:调用完该函数后,c1中存放的是c2原来的元素,c2中存放的则是c1原来的元素。c1和c2的类型必须相同。该函数的执行速度通常要比将c2的元素复制到c1的操作快
c.assign(b, e) 重新设置c的元素:将迭代器b和e标记的范围内所有的元素复制到c中。b和e必须不是指向c中元素的迭代器。
c.assign(n, t) 将容器c重新设置为存储n个值为t的元素
如果在不同(或相同)类型的容器内,元素类型不相同但是相互兼容,则其赋值运算必须使用assign函数。例如,可通过assign操作实现将vector容器中一段char*类型的元素赋给string类型的list容器。
由于assign操作首先删除容器中原来存储的所有元素,因此,传递给assign函数的迭代器不能指向调用该函数的容器内元素。
8、vector类提供了两个成员函数:capacity和reserve,使程序员可与vector容器内存分贝的实现部分交互工作。capacity操作获取容器需要分配更多的存储空间之前能够存储的元素总数,而reserve操作则告诉vector容器应该预留多少个元素的存储空间。
9、本质上,适配器是使一事物的行为类似于另一事物的行为的一种机制。容器适配器让一种已存在的容器类型采用另一种不同的抽象类型的工作方式实现。例如,stack(栈)适配器可使任何一种顺序容器以栈的方式工作。
默认的stack和queue都基于deque容器实现,而priority_queue则在vector容器上实现。在创建适配器时,通过将一个顺序容器指定为适配器的第二个类型实参,可覆盖其关联的基础容器类型:
stack< string, vector<string> > str_stk; // 使stack基于vector实现
对于给定的适配器,其关联的容器必须满足一定的约束条件。stack适配器所关联的基础容器可以是任意一种顺序容器类型。因此,stack栈可以建立在vector、list或者deque容器之上。而queue适配器要求其关联的基础容器必须提供push_front运算,因此只能建立在list或者deque容器上,而不能建立在vector容器上。priority_queue适配器要求提供随机访问功能,因此可建立在vector或deque容器上,但不能建立在list容器上。
10、所有适配器都定义了两个构造函数:默认构造函数用于创建空对象,而带一个容器参数的构造函数将参数容器的副本作为其基础值。例如,架设deq是deque<int>类型的容器,则可用deq初始化一个新的栈,如下所示:
stack<int> stk(deq);