C++复习day8:友元、异常、string类与标准模板库(依据C++premier plus)

基于《C++premier plus》第13、14章学习整理:
 

第十三章 友元、异常和其他

一、友元
1.友元类:friend class Remote;(其声明位置无关紧要)友元类的所有方法都可以访问该类的私有成员和保护成员(对其对象进行操作)。(这种方式本身注明了Remote是一个类,所以不需要前向声明)
2.友元成员函数:friend void Remote::set_chan(TV & t,int c);(注意这种形式需要在该类前先有Remote类定义的存在)
3.其他友元关系
(1)可设置两类互为友元类,此时注意按A/B顺序编写,则A只能声明B相关方法而不能实际定义,B可以定义A的相关方法,然后再通过类外定义成员函数对A缺失的操作实体进行补全。
(2)可以一个函数同时声明是多个类的友元
 
二、类的嵌套:在另一个类中声明的类
1.包含其的类可以随意使用它
2.其他模块根据权限限制再通过作用域解析运算符进行调用
3.外界定义其方法,形如 Queue::Node::Node(参数){}
4.在外部类访问控制的前提下(已经确认可以对该内部类进行访问时),包含类的派生类可以访问其私有部分外的成员,外部模块只能访问其公有成员。
5.模板中正确使用嵌套不会带来问题。
 
三、异常
1.判断语句配合中断程序:使用abort()<有提示语句>或exit()<无提示语句>在判断条件后进行问题程序的中断<直接终结程序不会回到main>
2.返回错误码:判断后返回标志值表示运行的状态,数据的传输则通过指针参数进行
3.使用全局变量判断程序状态
4.异常机制:
(1)try代码块表示异常激活代码块;catch(可捕获的异常类型)表示异常处理程序;throw进行显式的异常抛出(可以接类或者字符串);
(2)throw的语句将会中止函数的执行,导致程序按照函数的调用序列后退直到找到包含try块的函数寻找匹配的处理程序<过程中进行的栈退解过程将会执行自动变量的销毁和析构的执行>。
(3)默认情况下<没有找到相应的处理程序>将会调用abort进行中止。
(4)可以定义异常类便于catch块进行错误类型的划分<最好是继承自exception库中的相关方法>
(5)在函数声明上显式表示可抛出异常的异常规范机制已经基本被废止,新版本中允许使用noexcept表示指定方法不会产生异常
(6)可在catch的异常处理程序中使用throw表示相同方法的继续抛出(重新引发)。
(7)引发异常时编译器总是将异常复制并进行传递,即便对引用进行捕获,因为实际上异常本体已经作为自动存储被销毁了。
(8)异常的引发常常与创建同步如throw problem("说明字符串");
(9)基类的引用可以引发派生类对象(仅第一个引发),所以对一个异常类继承层次结构需要将基类放在下面。可以用catch(...)表示捕获任何类型;
(10)由于特性:
1.在派生类中重新定义基类的方法:
直接在派生类中定义与基类方法同名同参的方法,在调用该方法时编译器会根据所声明的指针/引用/对象类型来选择调用
2.使用虚方法:
在基类方法前加上virtual关键字(派生类里可以不加)然后同名同参,在调用该方法时编译器会根据指针/引用/对象的内容物实际的类型来选择调用方法。
所以虽然异常使用引用并不能提高效率,但可以防止派生类对象特性的丢失
 
四、使用异常机制
1.继承相关:
(1)可以从包括exception(基本的异常基类)、logic_error系列(处理通常可修复的逻辑异常)、runtime_error系列(处理运行时异常)、bad_alloc(处理new导致的内存分配问题/可以用判断new内存为空指针的方式替代)进行异常类的派生
(2)派生的异常类通常可以在创建时进行提示字符串的指定,他们都包含了用于描述错误的方法what();
(3)异常类可以和通常类一样使用组合、嵌套等方式处理
2.迷失的异常处理:
(1)在没有匹配的处理代码块或与异常规范机制不匹配时调用函数terminate<该方法默认调用abort可以通过set_terminate(函数名)的方式对其进行修改>
(2)由于异常规范机制嵌套导致的不匹配将会调用unexpected()方法的调用<默认调用terminate >同样可以用过set_unexpected()自定义,但这种方法对替代方法有较为严格的要求。
3.异常处理时记得与动态内存分配结合,管理好开辟出来的空间。
 
五、RTTI(运行阶段类型识别)———是一种可能不被编译器理解的新机制
1.功能:用于了解到对象变量(比如上转类型)真实的类型,来调用其特有的方法
2.必要条件:只被允许用于定义了虚函数的类
3.三组件:
(1)了解指针转换是否安全的运算符,形如dynamic_cast<Superb *>(pg);如果pg可以完整安全转换到该指针则返回对象地址,否则返回空指针
(2)类型比对运算符[可以投入类名或结果是对象的表达式](需要引入<typeinfo>),形如typeid(Magnificent) ==typeid(*pg);其运算符返回值其实是投入类的信息type_info对象,也可以调用typeid(Magnificent).name()方法得到相关数据(大多时候能得到类名)。
4.警告:
(1)即时编译器支持RTTI也可能默认关闭该特性导致编译成功而运行失败,请查看文档和菜单选项
(2)可以用虚函数解决就用虚函数,RTTI不被认为是一个通用的良好机制。
 
六、类型转换运算符(比起强转加以审查和限制,更加安全了)
1.dynamic_cast:形如pl=dynamic_cast<Low *> ph,仅当pl拥有ph的基类类型时赋值生效否则返回空指针
2.const_cast:形如High *=const_cast<High *>(pbar),仅当<>转换目标和()实际内容类型只相差一个const标识时成立,但实际上如果把指向常量的指针const抹掉修改操作也是不发生作用的。
3.static_cast:只有转换目标和转换变量之间存在隐式调用转换的可能性才进行转换,否则返回空指针。
4.reinterpret_cast:强行将内存的值重新解释的转换方法。
 

第十六章string和标准模板库

一、string类:需要引入<string>而非<cstring>[这表示的是c风格字符串]
1.实际上string是模板具体化basic_string<char>的一个typedef,拥有7+2种构造方法
2.string类的输入:
(1)c风格三种输入:直接cin、cin.getline()、cin.get()/string两种:直接cin、getline();行读取都可以设置中断的哨兵符(指定后换行符会被认作普通符号处理8 )
(2)功能上string版本的getline方法将自动调整string对象的大小至正好存储输入的字符。
3.使用字符串:
(1)str.leath()和str.size()返回字符串字符数
(2)string的关系运算符已经实现根据ascii的重载
(3)字串查找方法:find、rfind(查找最后一次出现位置)、find_first_of(第一次出现位置)、find_last_of(最后一次出现位置)、find_first_not_of(查找第一个不包含在参数中的字符)
(4)算术运算符在string中也完成了符合逻辑的重载
(5)库中还包含了部分删除、部分替换、部分比较、字串提取、字串互换等方法的实现
(6)reserve方法请求内存块最小长度、capacity返回分配给字串的内存块大小。
(7)str.c_str()方法将string字符串返回成符合c风格的指针
4.字符串的种类:basic_string有四个具体化,string、wstring、u16string、u32string,他们都有对应的typedef进行使用的简化。
 
二、智能指针模板类:类似指针的类对象,使他们能够实现额外的功能(此处为辅助动态内存分配)
1.使用:需要包含头文件<memory>/自动进行指针的内存释放,不需要delete
(1)auto_ptr:c++11已摒弃,形如auto_ptr<double> pd(new double);
(2)unique_ptr:形如unique_ptr<double> pd(new double);
(3)shared_ptr:形如shared_ptr<double> pd(new double);
2.注意:
(1)不可用非new内存块的目标作为参数
(2)采用简单所有权防止其赋值后一个内存被释放两次,但这造成用其进行赋值后会变成已被释放的空指针;相比而言unique_ptr使用严格所有权方式会提前报告错误,而使用更高智能指针的shared_ptr(类似linux进行的连接计数)跟踪直达无使用才进行delete
3.选择:
(1)需要指向同一对象多个指针时采用shared_ptr
(2)不需要指向同一对象多个指针时采用unique_ptr
 
三、标准模板类:内容量大。详情需查阅资料,以下为概述
1.模板内容包括了容器(同质存储单元集)迭代器(用于遍历容器的对象)函数对象(类似函数的对象<可以是类对象获函数指针>)算法的模板
2.STL模板有一个可选参数用于指定管理内存的分配器对象,默认是使用new和delete的allocator<T>
3.列举模板类vector:
(1)形如vector<int> ranings(5)创建并制定初始长度,可以通过下标索引,且动态内存分配
(2)容器通用方法:size(返回容器元素数目)swap(交换两个容器内容)begin(返回指向容器第一个元素的迭代器)end(返回一个超过容器尾部的迭代器<可以认为迭代器是广义指针>)
(3)创建相关迭代器(适用于任何容器):
    <1>vector<double>:: iterator pd;进行容器声明
            当有vector<double> scores;时
           pd=scores.begin();获得该容器
    <2>auto pd=scores.begin();会更方便
(4)使用相关迭代器:如++pd就可以让指针后移一位
        则可以使用进行遍历如:
for (pd=scores.begin();pd!=scores.end();pd++)
    cout<<*pd<<endl;
(5)push_back方法往后添加元素,可以动态改变vector长度
(6)erase方法删除给定区间<需要用迭代器指定位置>的元素
(7)insert方法指定另一个容器对象的区间<通过第二第三个迭代器参数>作为来源对第一个参数迭代器位置进行插入<通过尾指针可以做到批量添加>
4.代表性STL相关方法:没有为STl容器本身定制太多操作方法,这些操作通过非成员函数完成来简化编程
(1)for_each(books.begin(),bookes.end(),ShowReview) 参数一二为容器迭代器,参数三为使用在该区间元素上的方法。
(2)random_shuffle(books.begin(),bookes.end())将该区间的元素进行随机排列
(3)sore()排序方法
    <1>sort(books.begin(),bookes.end())将会依据该对象中定义的关系运算符<进行升序排序
    <2>更灵活则sort(books.begin(),bookes.end(),WorseThan)可以输入第三个参数作为比较方法,通过非成员的方式进行自定义的比较方法设定(一定要以前两参为参数且返回bool值的方法)
5.基于范围的for循环是为STL设计的
(1)for(auto x:books)ShowReview(x);只能读副本
(2)for(auto & x:books)ChangeEle(x);对引用修改原文<for_each做不到>
补充:重载++运算符时用无参数表示前缀重载,参数int表示后缀的重载
 
四、泛型编程
1.通过获取广义指针类型也就是迭代器,使用同一种算法表示链表或数组等方式的数据的操作,实现数据类型与操作的分离
2.迭代器类型:不同算法对迭代器要求不同<目的是编写算法是尽量使用要求低的迭代器>(不能类派生,是概念的层次结构)
(1)输入迭代器:可递增不倒退,单次通行(重复不保证顺序统一)可读取不修改的迭代器(只读)
(2)输出迭代器:可递增不倒退,单次通行(重复不保证顺序统一)可修改不读取的迭代器(只写)
(3)正向迭代器:可多次通行,可读可写。
(4)双向迭代器:有正向所有功能且附加递减运算符实现了反向行为
(5)随机访问迭代器:具有双向迭代器能力且附加了随机访问能力
3.迭代器是广义指针,所以当然指针也可以使用为迭代器写的算法
4.其他迭代器:由include<iterator>引入
(1)表示输入输出流的迭代器ostream_iterator/istream_iterator
(2)反向迭代器reserve_iterator,形如copy(dice.rbegin(),dice.rend(),out_iter);反向输出容器区间内容
(3)back_insert_iterator(尾部插入)insert_iterator(选点插入)front_insert_iterator(头部插入)
<比如对copy方法的增强,普通迭代器是复制进行位置替换,声明为其他迭代器可以做到扩展操作>
形如copy(s2,s2+2,back_insert_iterator<vector<string>>(words));可以做到尾部添加且自动进行长度扩展
5.容器:
(1)序列
        <1><vector>自动内存管理、动态长度改变最简单的序列类型容器,除非有特殊要求,否则默认选择它
        <2><deque>双端队列,特别优化了首位的插入删除操作速度
        <3><list>双向链表,强调的是任何点位快速的插入和删除,不支持随机访问
        <4><forward_list>最简单的单链表
        <5><queue>受限的基本队列,仅限头出、尾进,查看首位和查看队列状态,不支持遍历
        <6><priority_queue>同queue区别在于自动将数值最大的移到队首
        <7><stack>不支持遍历,基本栈,仅支持栈顶弹出、查看、压入和查看栈状态
        <x><array>非STL容器,不可调长度,但部分STL方法适用于它
(2)关联容器
        <1><set>关联集合,可翻转可排序,键唯一(不存储多个相同值),声明时可确定排序方法,具备数学集合的运算方法
        <2><multiset> multiset支持重复,而set会去重
        <3><map>一键对应一个实例
        <4><multimap>可翻转可排序的键值影射,同一个键可与多个值相关联,默认根据键排序,插入是按顺序的所以不需要指出位置
(3)无序关联容器:底层使用哈希表提高添加删除和查找的效率
6.容器重载的==使用迭代器进行容器的比较,因此如果deque和vector对象内容相同,他们就是相等的
 
五、函数对象(即函数符)
1.很多STL算法使用的都是函数符,即可以以函数方式和()结合使用的任意对象。这包括函数名、指向函数的指针和重载了()运算符的类对象
2.内置的运算符都有相应的函数符
3.通过函数适配器转化自适应函数,形如binder1st(f2,val) f1;将函数f2的参数1与val绑定命名f2即可参与需要自适应一元函数的方法。同理binder2nd是与第二个参数绑定
4.c++11提供了lambda作为函数指针和函数符的替代品(第十八章)
 
六、算法:头文件有algorithm和numeric
1.通常以_copy结尾的STL算法都是复制算法,即使用副本在指定位置进行操作,就地算法则对来源进行修改
2.设计string类时考虑到了STL,所以可以对其使用如sort、end、begin等STL算法。
3.通常使用STL成员方法更好,因为这样通常含有自动的长度管理等帮助,如remove成员方法自动修改长度,而外部方法则需要配合erase才能完成整个删除过程
4.STL的算法是内联的
 
七、其他库
1.<complex>提供复数模板和运算处理
2.<random>提供更多随机数功能
3.<valarray>数值数组及其操作,但不是STL的一部分
4.c++11增加了接受valarray为对象的模板函数begin和end因此使用begin(vad)而不是vad.begin()可以将之用于STL算法当中
5.扩展的下表指定slice,形如varient[slice(1,4,3)]=10;表示将varient的第1,4,7,10三项设为10
6.c++11新增模板initializer_list:即形如std::vector<double> payments{80.96,10.21,30.56,8.88}可以用列表进行容器初始化
(1)该方式默认优先调用含initializer_list作为参数的构造函数,其次是等同()调用一般构造函数,但具有拒绝隐式转换缩窄的功能
(2)要使用nitializer_list需要引入头文件<nitializer_list>
 
 
 
 
 
 
 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值