第15章
- 友元类可以声明在公有,私有,保护任意部分。
class Tv
{
public:
friend class Remote;
......
}
class Remote
{
.....
}
这样Remote可以使用Tv的私有成员。
class Tv; // forward declaration
class Remote
{
.....
}
class Tv
{
public:
friend void Remote::set_chan(Tv & t, int c);
.....
}
这样只有Remote::set_chan(Tv & t, int c)成为了友元方法。
注意互为友元的时候,对于使用Remote对象的Tv方法,其原型可在Remote类声明之前声明,但必须在Remote类声明之后定义。
嵌套类
声明位置 | 包含它的类是否可以使用它 | 从包含它的类派生而来的类是否可以使用它 | 在外部是否可以使用 |
---|---|---|---|
私有部分 | 是 | 否 | 否 |
保护部分 | 是 | 是 | 否 |
公有部分 | 是 | 是 | 是,通过类限定符来使用 |
调用abort()函数可以终止程序(包含头文件cstdlib)
throw关键字表示引发异常,紧随其后的值指出了异常的特征。
C++通常通过将信息放在栈中来处理函数调用,普通函数程序会将函数指令的地址(返回地址)放到栈中,执行完毕后,程序再确定从哪开始执行。然而,函数异常终止之后,程序也将释放栈中的内存,但不会再释放栈的第一个返回地址后停止,而是继续释放栈,直至找到一个位于try块中的返回地址。然后控制权转到块尾的异常处理程序。
exception类
- stdexcept异常类:分为logic_error和runtime_error类
logic_error包括domain_error, invalid_argument, length_error, out_ot_bounds
runtime_error包括range_error, overflow_error, underflow_error - bad_alloc异常:
在头文件new中。在new请求内存出现分配问题时触发。 - C++提供了一种在失败时返回空指针的new。用法:
int * pi = new (std::nothrow) int;
或者int *pa = new (std::nowthrow) int[500]
- stdexcept异常类:分为logic_error和runtime_error类
异常同样可以继承。程序15.14,书634页的例子。
未捕获异常不会导致程序立刻异常终止,程序会先调用terminate(),默认情况下,terminate()会调用abort()。可以调用set_terminate()函数来修改terminate()的行为。
如果发生意外异常,会调用unexpected()函数,默认调用abort(),同样可以使用set_unexpected()函数来修改行为。RTTI(运行阶段类型识别)
- dynamic_cast运算符
可以确定转换是否安全,例如:Superb* pm = dynamic_cast<Superb *>(pg)
。如果能安全转换则返回对象的地址,否则返回一个空指针。 - typeid运算符用于确定两个对象是否为同种类型。
typeid(Megnificent) == typeid(*pg)
如果pg是空指针,则会引发bad_typeid异常。
- dynamic_cast运算符
类型转换符:
- dynamic_cast在类层次结构中进行向上转换。
- const_cast只能用于改变值为const或volatile
- static_cast当转换的类型是原类型所属的类型时才可以使用。
- reinterpret_cast用于底层编程,一般用不到。
第16章
string类的构造函数
1.string(const char * s)
说明:将string对象初始化为s指向NBTS。NBTS为null-byte-temnated string的缩写,表示以空字符结束的字符串——传统的C字符串。
2.string(size_type n,char c)
说明:创建一个包含n个元素的string对象,其中每个元素都被初始化为字符c
3.string(const string & str,string size_type n = npos)
说明:将string对象初始化为对象str中从位置pos开始到结尾的字符,或从位置pos开始的n个字符
4.string()
说明:创建一个的string对象,长度为0
5.string(const char * s, size_type n)
说明:将string对象初始化为s指向的NBTS中的前n字符,即使超过了NBTS端
6.template< clas Iter > string(Iter begin,Iter end)
说明:将string对象初始化为区间[begin,end]内的字符,其中begin和end的行为就像指针,用于指定位置,范围包括begin在内,但不包括end
7.string(const string & str, string size_type pos = 0, size_type n = npos)
将string对象初始化为对象str中从位置pos开始到结尾的字符,或从位置pos开始的n个字符。
8.string(string && str) noexcept
将一个string对象初始化为string对象的str,并可能修改str
9.string(initializer_list< char > il)
将一个string对象初始化为初始化列表il中的字符
注意:区间是包前不包后。string类的输入:
string stuff;
cin>> stuff;
getline(cin, stuff);
getline(stuff, ':');
char info[100];
cin>>info;
cin.getline(info,100);
cin.get(info, 100);
cin.getline(info,100,':');
string类的find方法:
原型如下:
(1)size_t find (const string& str, size_t pos = 0) const; //查找对象–string类对象
(2)size_t find (const char* s, size_t pos = 0) const; //查找对象–字符串
(3)size_t find (const char* s, size_t pos, size_t n) const; //查找对象–字符串的前n个字符
(4)size_t find (char c, size_t pos = 0) const; //查找对象–字符
结果:找到 – 返回 第一个字符的索引;没找到–返回 string::npos。capacity()返回当前分配给字符串的内存块的大小,函数reserve()将字符串的容量设置为至少size. 如果size指定的数值要小于当前字符串中的字符数(亦即size < this→size()), 容量将被设置为可以恰好容纳字符的数值。最大的用处是为了避免反复重新分配缓冲区内存而导致效率降低,或者在使用某些STL操作(例如std::copy)之前保证缓冲区够大。
智能指针:过期内存自动释放。
内存指针必须显式转换,不能隐式转换,例如:
shared_ptr<double> pd;
double *p = new double;
pd = p; //错误写法,隐式转换
pd = shared_ptr<double>(p); // 显式转换注意不能让智能指针指向同一个对象,因为这样会删除一个对象两次。为了解决, auto_ptr和unique_ptr采用的是所有权概念,shared_ptr使用的是引用计数的方法。
- 如果程序将unique_ptr赋给另外一个,在unique_ptr只作为一个临时右值时是允许的,但是如果要存在一段时间,不允许。
- 使用new分配内存时,才能使用auto_ptr和shared_ptr,不能使用new []。unique_ptr有new和new[]的版本。
STL
- 模板类vector代替数组,在< type >中声明数组中的类型,变量名后用括号()指明数组元素个数。有
函数 | 作用 |
---|---|
swap() | 交换 |
begin() | 返回第一个元素的迭代器 |
end() | 返回最后一个元素的迭代器 |
push_back() | 将元素添加到队尾,并自动加长长度 |
erase() | 有两个迭代器参数,删除指定区间的元素 |
insert() | 三个参数,第一个参数是插入的位置,后两个是插入区间 |
- 迭代器:广义指针,可以是指针,也可以是对其执行类似指针的操作。声明:
vector<double>::iterator pd
可执行类似指针的操作。
pd = scores.begin();
*pd = 2;
++pd;
超过结尾:一种迭代器,指向容器的最后一个元素后面的那个元素。
STL函数:
函数 | 作用 |
---|---|
for_each() | 函数指向容器每个元素,但是不能改变值 |
Random_shuffle() | 有两个迭代器参数,随机排列区间内的元素 |
sort() | 排序 |
- 迭代器类型:输入,输出,正向,双向,随机访问迭代器。
固定时间和线性时间复杂度
七种主要容器:
- vector(前面已经介绍过)
- deque表示双端队列,从开始位置插入和删除元素时间固定。
- list表示双向链表,任意位置插入和删除时间固定,但是不能随机访问。其成员函数:
assign() 给list赋值
back() 返回最后一个元素
begin() 返回指向第一个元素的迭代器
clear() 删除所有元素
empty() 如果list是空的则返回true
end() 返回末尾的迭代器
erase() 删除一个元素
front() 返回第一个元素
get_allocator() 返回list的配置器
insert() 插入一个元素到list中
max_size() 返回list能容纳的最大元素数量
merge() 合并两个list
pop_back() 删除最后一个元素
pop_front() 删除第一个元素
push_back() 在list的末尾添加一个元素
push_front() 在list的头部添加一个元素
rbegin() 返回指向第一个元素的逆向迭代器
remove() 从list删除元素
remove_if() 按指定条件删除元素
rend() 指向list末尾的逆向迭代器
resize() 改变list的大小
reverse() 把list的元素倒转
size() 返回list中的元素个数
sort() 给list排序
splice() 合并两个list
swap() 交换两个list
unique() 删除list中重复的元素 - forward_list表示单链表,只需正向迭代器,不可反转。
- queue是一种容器适配器,它给予程序员一种先进先出(FIFO)的数据结构。操作函数:
back()返回最后一个元素
empty()如果队列空则返回真
front()返回第一个元素
pop()删除第一个元素
push()在末尾加入一个元素
size()返回队列中元素的个数 - priority_queue操作和queue相同,最大的元素被移到队首。
- stack表示栈,操作:
1.入栈:如s.push(x);
2.出栈:如 s.pop().注意:出栈操作只是删除栈顶的元素,并不返回该元素。
3.访问栈顶:如s.top();
4.判断栈空:如s.empty().当栈空时返回true。 - array
关联容器:值和键关联在一起。
- set:关联集合,可反转,排序,键值唯一,不能存储多个相同的值。例如:
set<string> a
模板第二个参数可选,可以是对键进行排序的比较函数或对象。默认有默认值。
常用操作:
1.元素插入:insert()
2.中序遍历:类似vector遍历(用迭代器)
3.反向遍历:利用反向迭代器reverse_iterator。
例:
set< int> s;
……
set< int>::reverse_iterator rit;
for(rit=s.rbegin();rit!=s.rend();rit++)
4.元素删除:与插入一样,可以高效的删除,并自动调整使红黑树平衡。
set< int> s;
s.erase(2); //删除键值为2的元素
s.clear();
5.元素检索:find(),若找到,返回该键值迭代器的位置,否则,返回最后一个元素后面一个位置。
set< int> s;
set< int>::iterator it;
it=s.find(5); //查找键值为5的元素
if(it!=s.end()) //找到
cout<<*it << endl;
else //未找到
cout<<”未找到”;
6.自定义比较函数
(1)元素不是结构体:
例:
//自定义比较函数myComp,重载“()”操作符
struct myComp
{
bool operator()(const your_type &a,const your_type &b)
[
return a.data-b.data > 0;
}
}
set< int,myComp>s;
……
set< int,myComp>::iterator it;
(2)如果元素是结构体,可以直接将比较函数写在结构体内。
例:
struct Info
{
string name;
float score;
//重载“<”操作符,自定义排序规则
bool operator < (const Info &a) const
{
//按score从大到小排列
return a.score < score;
}
}
set< Info> s;
……
set< Info>::iterator it; - multimap:可反转,经过排序的关联容器,但键和值的类型不同,且同一个键可能与多个值相关联。
基本操作:
- set:关联集合,可反转,排序,键值唯一,不能存储多个相同的值。例如:
begin() | 返回指向第一个元素的迭代器 |
---|---|
clear() | 删除所有元素 |
count() | 返回一个元素出现的次数 |
empty() | 如果multimap为空则返回真 |
end() | 返回一个指向multimap末尾的迭代器 |
equal_range() | 返回指向元素的key为指定值的迭代器对 |
erase() | 删除元素 |
find() | 查找元素 |
get_allocator() | 返回multimap的配置器 |
insert() | 插入元素 |
key_comp() | 返回比较key的函数 |
lower_bound() | 返回键值>=给定元素的第一个位置 |
max_size() | 返回可以容纳的最大元素个数 |
rbegin() | 返回一个指向mulitmap尾部的逆向迭代器 |
rend() | 返回一个指向multimap头部的逆向迭代器 |
size() | 返回multimap中元素的个数 |
swap() | 交换两个multimaps |
upper_bound() | 返回键值>给定元素的第一个位置 |
value_comp() | 返回比较元素value的函数 |