4C++高级特性.ppt_第1页
4C++高级特性.ppt_第2页
4C++高级特性.ppt_第3页
4C++高级特性.ppt_第4页
4C++高级特性.ppt_第5页
已阅读5页,还剩119页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、面向对象程序设计与实践2C+高级特性,交换与智能控制研究中心 网络与交换技术国家重点实验室 网络技术研究院 北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名空间 异常处理,北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名空间 异常处理,北京邮电大学,什么是重载?,重载函数(overloaded function)是一种特殊函数 同时满足以下三个条件的就是重载函数 函数名相同 在相同的域中被声明 参数不同 举例:编译器提供的运算符重载 Int类型:2 + 3,7 - 2, 8 * 3,6 / 2 Double类型:2.3 + 4.5,3.3 1.5,2

2、.4 * 3.2,9.0 / 2.5 编译器仅提供了基本类型的运算符重载功能,函数和自定义类型需要程序员自己实现重载功能,北京邮电大学,为什么要重载?,例如,如下函数,返回参数中的最大值 Int i_max(int, int); Int vi_max(const vector 特点:执行相同的功能 返回参数集合中的最大值 但是,从用户的角度来看,最好只有一种操作 用户并不(需要)关心参数类型等实现细节,北京邮电大学,为什么要重载?,局限性:同一个域中出现的名字必须指向唯一实体 程序员必须记住每一个名字 函数重载的目的:把程序员从复杂的词汇中解放出来 举例:通过函数重载 int ix = max

3、( 3, 5); Vector vec = ; Int iy = max(vec);,北京邮电大学,如何实现重载?,重载函数要求参数表是唯一的,满足以下条件任一均可: 参数的个数可以不同 或者,参数类型可以不同 例如,以下定义是合法的重载函数: Int max(int, int); Int max(int, int, int); Int max(const vector ,北京邮电大学,重载解析过程,当一个函数名在一个域中被声明多次时,编译器按如下步骤解释第二个(和后续的)声明: 第一步,如果参数表中的参数的个数或类型不同,则认为两个函数是重载的,北京邮电大学,重载解析过程,第二步,如果两个函

4、数的返回类型和参数表精确匹配,则第二个声明被视为第一个的重复声明 例如,以下声明了同一个函数 Void print( const string 参数表的比较过程与参数名无关,北京邮电大学,重载解析过程,第三步,如果两个函数的参数表相同,但返回类型不同,则第二个声明被视为第一个的错误重复声明,并标记为编译错误 例如,以下两个函数不是重载函数 Int getValue(istream 返回类型不能用来区分两个重载函数,北京邮电大学,重载解析过程,为什么返回值类型不作为重载判定条件? 返回值有时被程序员忽略 如:getValue(cin); / 略过一个值 类型扩展、类型转换等的影响 如:doubl

5、e d = getValue(cin); int类型也可以传递给double变量,因此无法判断调用哪个函数(返回int的?还是返回double的?),北京邮电大学,重载解析过程,如何定义只有返回值不同的函数? 例如,刚才的两个getValue() 建议,在函数名称中包含返回值类型 Int getInt(istream 这两个函数不是重载函数,因为函数名不同 很简单地解决返回值不同的问题 函数名称的可读性更好 重载,既不是万能的,也不是必须的,根据实际需要来使用,北京邮电大学,重载解析过程,第四步,如果两个函数的参数表中,只有默认实参不同,则第二个声明被视为第一个的重复声明 例如,以下两个定义声

6、明的是同一个函数 Int max( int *ia, int sz); Int max( int *, int = 10); 原因,默认实参并没有减少参数个数,只是这个参数的值是由编译器来提供的,北京邮电大学,重载解析过程其他细节情况,Typedef的判断:视为相同的类型 例如,以下定义了同一个函数 Typedef double Dollar; Void deposit( Dollar ); Void deposit( double ); 原因,typedef只是提供了一个别名,并未创建一个新类型 类似的,const和volatile类型的参数,在重载解析时不考虑这两个修饰符 例如,以下定义了

7、同一个函数 Void foo( int ); Void foo( const int ); 又注,这里关于const的说明不适用于:引用类型的形参,北京邮电大学,重载与作用域,局部声明的函数,将屏蔽而不是重载外层作用域中的同名函数 例如, void print( const string /ok, double类型被隐式地转成int 提示:通常,局部声明函数是一种不明智的选择。函数的声明应放在文件中。 此处为了用于说明问题,北京邮电大学,重载确定的步骤,重载确定:即函数匹配,是将函数调用与重载函数集合中的一个函数相关联的过程 以如下函数和函数调用为例: void f(); void f( in

8、t ); void f( int, int ); void f( double, double = 3.14 ); f(5.6); / 此时实际应当调用哪个函数? / 实际调用 void f( double, double );,北京邮电大学,重载确定的步骤,第一步,候选函数 确定该调用所考虑的重载函数集合 候选函数,是与被调用函数同名的函数,并且在调用点上,它的声明可见 本例中,有四个名为f()的候选函数 void f(); void f( int ); void f( int, int ); void f( double, double = 3.14 );,北京邮电大学,重载确定的步骤,第

9、二步,选择可行函数 从候选函数中选择一个或多个函数,它们能够用该调用中指定的实参来调用。 可行函数必须满足的两个条件: 函数的形参个数与该调用的实参个数相同 每一个实参的类型必须与对应形参的类型匹配,或者可被隐式转换为对应的形参类型 本例中,调用f( 5.6 ); void f(); / 形参个数不符合,不是可行函数 void f( int ); /参数个数匹配,int类型可隐式转换,是可行函数 void f( int, int ); / 形参个数不符,不是可行函数 void f( double, double = 3.14 ); / 形参个数符合,因为有默认实参,是可行函数,北京邮电大学,重

10、载确定的步骤,第三步,寻找最佳匹配(如果有的话) 确定与函数调用中使用的实际参数匹配最佳的可行函数 匹配原则:实参类型与形参类型越接近则匹配越佳,精确类型匹配比需要转换的匹配好 本例中,调用f(5.6); void f( double, double = 3.14 ); / 精确匹配,最佳 void f( int ); / 需要类型转换,不如前一个函数,北京邮电大学,匹配结果的可能性,编译器找到与实参最佳匹配的函数,并生成调用该函数的代码 找不到形参与实参相匹配的函数,编译器将给出编译错误的信息 即可行函数(第二步)的结果为空集 存在多个与实参匹配,但没有一个是明显的最佳选择 这也是错误,该调

11、用具有二义性,北京邮电大学,编译器的函数名修饰(1/4),函数名称需保证唯一性,否则无法正确链接 编译时进行函数名修饰,产生唯一的函数名称 适用于C+中的所有函数,包括非重载函数 修饰方法根据:函数类型、函数调用类型、返回值类型、参数个数、参数类型,等等 详见 具体的函数名修饰方法通常没必要知道,北京邮电大学,编译器的函数名修饰(2/4),void globalHello(); void globalHello( int );,北京邮电大学,class Empty public: void classHello(); void classHello( int ); ;,void _cdecl

12、globalHello(int) (?globalHelloYAXHZ),C+函数修饰以“?”开始,源代码中的函数名称,函数调用方式,这里是_cdecl,X:返回值类型为void H:输入参数类型为int,结束标记,编译器的函数名修饰(3/4),void globalHello(); void globalHello(int);,北京邮电大学,class Empty public: void classHello(); void classHello(int); ;,public: void _thiscall Empty:classHello(void) (?classHelloEmptyQ

13、AEXXZ),类名,public成员函数,X:返回值类型为void X:输入参数类型为void,结束标记。无参数,所以省略,编译器的函数名修饰(4/4),不希望编译器进行函数名修饰? 用于动态链接库(DLL)等,供第三方调用 extern “C” ,北京邮电大学,extern “C” void globalNoRename(); ,为什么要重载赋值和拷贝构造函数?,空类是否没有任何函数? 举例:class Empty ; 答案:不是,C+编译器会(在调用时)自动产生 一个拷贝构造函数 一个赋值操作符 一个析构函数 一个默认构造函数(如果没有定义任何构造函数) 并且,都是public inlin

14、e的 class Empty public: Empty() / 默认构造函数 Empty(const Empty /非法定义 思考:为什么不可以? 原因,强制重载操作符不能重新定义用于基本类型的操作符的含义,否则容易让人混淆和难以理解 优先级和结合性是固定的 操作符的优先级、结合性或操作数数目均不能改变,北京邮电大学,重载操作符的要求,不再具有短路求值特性 短路求值举例: bool b = false; if ( b 没有创建临时对象,性能略优,北京邮电大学,Test Test:operator+ () Test res(this-value+); return res; ,Test ,重载

15、操作符和友元的关系,非成员函数的操作符,通常设为类的友元 原因:操作符通常需要访问类的私有数据和方法,北京邮电大学,例如: class Complex friend Complex operator+(Complex ,使用重载运算符,方式一:与内置类型上使用操作符的方法一样 以前面的Complex类为例 Complex c2, c3; cout c2 + c3 endl; 方式二:像调用函数一样调用重载操作符函数 cout operator+(c2, c3) endl;,北京邮电大学,重载操作符的设计经验原则,不要重载具有内在含义的操作符 取地址( 解释为:x = ( y = ( z = 1

16、5 ) ); 对象如何能使用连锁赋值? class Widget public: Widget,北京邮电大学,operator=的最佳实践,最佳实践2:实现“自我赋值” 举例:Widget w; w = w; 这是合法行为,因此用户可以/可能这样用 ai = aj; *pa = *pb; 可行但非最佳做法: /假设Widget类含一个Bitmap的指针pb Widget ,北京邮电大学,operator=的最佳实践,最佳实践2:实现“自我赋值” 更好的做法: /假设Widget类含一个Bitmap的指针pb Widget ,北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名

17、空间 异常处理,北京邮电大学,容器类,容器:容纳特定类型对象的集合 顺序容器(sequential container) 容器内的元素按其位置存储和访问 如,vector,list,stack等 关联容器(associative container) 通过键(key)存储和读取元素 如,map,set,multimap, multiset 容器类共享公共的接口 易于学习,学会一种就能使用另一种 每种实现提供不同的时间和功能的折衷 替换容器类型时,不需要修改代码,只需改变类型声明,北京邮电大学,顺序容器,标准库中定义的顺序容器相关类 三个顺序容器类型 Vector,支持快速随机访问 List,支

18、持快速插入/删除 Deque,即双端队列“double-ended queue”,读“deck” 区别:访问元素的方式,添加/删除元素等操作的运算代价 三种容器适配器(adaptor) 适配器,基于原始容器类型,定义新的操作接口,来适应基础的容器类型 Stack,后进先出(LIFO)栈 Queue,先进先出(FIFO)队列 Priority_queue,有优先级管理的队列 容器只定义了少量操作,额外操作由算法库提供,北京邮电大学,顺序容器的定义,头文件 #include #include #include 命名空间:using namespace std; 声明变量 Vector svec;

19、/ 存放string的vector List ilist; / 存放int的list Deque numbers; / 存放Complex 尖括号()内的是存放的类型,容器都是模板类 大多数情况下可以使用默认构造函数来初始化 程序更清晰,简短 可以达到最佳性能,容器也更容易使用,北京邮电大学,容器元素的初始化,将一个容器初始化为另一个容器的副本 vector ivec; vector ivec2(ivec); / 调用拷贝构造函数 list ilist(ivec); /错误,ivec不是list vector dvec(ivec); /错误,ivec存的是int 复制容器时,类型必须匹配,即容

20、器类型和元素类型都必须相同,北京邮电大学,容器元素的初始化,初始化为一段元素的副本 迭代器(Iterator),用于遍历容器中的元素 可以指定遍历的开始和结束位置,可以只是容器元素中的一部分 通过迭代器来初始化容器,就只复制迭代器指定的这部分元素 vector svec; list slist(svec.begin(), svec.end(); vector:iterator mid = svec.begin() + svec.size() / 2; / 定位到svec的中间位置 deque front(svec.begin(), mid); deque back(mid, svec.end(

21、); 可以在不同的容器类型之间复制数据 元素类型可以不直接相同,但需要兼容,即可以转换,北京邮电大学,容器元素的初始化,分配和初始化指定数目的元素 创建时,可显式指定容器大小和元素初始值 list slist(32, “hello”); /32份“hello” list ilist(32); /32个元素,每个初始化为0 若不提供初始化值,元素类型必须是基本或复合类型,或者提供默认构造函数 如果没有默认构造函数,则必须显式指定初始值 顺序容器可以指定容量,关联容器不支持,北京邮电大学,容器内元素的类型约束,容器元素类型必须满足的两个约束 元素类型必须支持赋值运算 元素类型的对象实例必须可以复制

22、 大多数类型都满足此条件 例外:引用不支持赋值运算,因此没有引用类型的容器 容器本身也满足以上条件,可以有存放容器的容器 Vector ivvec; 注意,必须用空格隔开两个相邻的,否则被视为,出现编译错误 IO库不支持复制和赋值,因此,也没有存放IO类型对象的容器,北京邮电大学,迭代器,每种容器类型都提供若干的迭代器类型 所有迭代器具有相同的公共接口,部分迭代器提供一些额外的操作 常用的迭代器运算 *iter,返回iter指向的元素 iter-mem,解引用,并且获取元素中的mem成员 +iter,iter+,指向容器中的下一个元素 -iter, iter-,指向容器中的前一个元素 iter

23、1 = iter2,比较是否指向容器中的同一个元素 iter1 != iter2,比较是否指向容器中的不同元素,北京邮电大学,迭代器范围,迭代器范围是标准库的基础 由一对迭代器来标记迭代器范围的首尾 分别指向同一个容器中的两个元素,或者超出末端的下一个位置 通常命名为first / last,或begin / end 范围是左闭合区间,即 first, last ) 表示从first,到last结束,但不包括last Last可以等于first,但绝对不能指向first之前的元素 思考,first和last没有指向同一个容器,会有什么情况?,北京邮电大学,迭代器范围,左闭合区间的编程意义 wh

24、ile ( first != last ) / 处理当前元素 +first; 思考,这种方式有什么优点和缺点? 对比,Java语言中的遍历代码 While ( iter.hasNext() ) Complex xyz = iter.next(); ,北京邮电大学,迭代器失效,一些操作会修改容器的内部状态,或移动容器内的元素,这些操作 使所有指向被移动元素的迭代器失效, 也可能同时使其他迭代器失效,难以预知 例如,调用erase()函数来删除容器元素 使用无效迭代器的问题 行为是未定义的,可能出现与悬挂指针相同的问题 可能会导致严重的运行时(runtime)错误 程序不一定会崩溃,因此难以测试和

25、调试,北京邮电大学,迭代器失效,解决方法 无法检查迭代器是否有效,也无法通过测试来发现迭代器是否失效 必须留意会使迭代器失效的操作 可以缩小要求迭代器有效的代码范围 将迭代器的使用限制在一个较小范围内和较小执行周期内 严格检查每一条语句 判断是否有元素添加或删除,从而相应调整迭代器的值,北京邮电大学,无解,顺序容器的操作,添加元素 push_back(),在容器尾部创建一个元素 如,ilist.push_back ( 10 ) ; insert(),在指定位置添加一个或者一段元素,有多个重载版本 如,slist.insert ( iter, “hello” ); /在iter迭代器的位置添加

26、添加元素可能会使迭代器失效,北京邮电大学,顺序容器的操作,容器大小相关的操作 size(),获取容器中的元素个数 empty(),返回容器是否为空 resize(n),调整容器的大小为n,若n小于容器当前大小,则删除多出来的元素,北京邮电大学,顺序容器的操作,访问元素 front(),返回第一个元素的引用 back(),返回最后一个元素的引用 cn,返回下标为n的元素的引用 只适用于vector和deque的容器 c.atn,返回下表为n的元素的引用 只适用于vector和deque的容器,北京邮电大学,顺序容器的操作,删除元素 erase(iter),删除迭代器iter所指的元素 erase

27、(iter1, iter2),删除迭代器范围iter1, iter2)内的元素 clear(),清空整个容器,北京邮电大学,容器的选用,Vector和deque 提供对元素的快速随机访问 代价,在容器任意位置插入或删除元素,比在容器尾部插入和删除的开销更大 List 任何位置都能快速插入和删除 元素的随机访问开销较大,北京邮电大学,容器的选用,通常,vector是最佳选择,除非找到使用其他容器的更好理由 选择容器类型的法则 如果数据规模不大,使用vector 程序要求随机访问元素,使用vector和deque 程序必须在容器中间位置插入或删除元素,使用list容器 程序不是在容器的中间位置,而

28、是在首尾部添加或删除元素,使用deque容器,北京邮电大学,关联容器,关联容器支持通过键来高效地查找和读取元素 关联容器的类型 map,关联数组,元素通过键来存储和读取 元素以“键-值”(Key-value)的形式,成对组织 set, 大小可变的集合 仅包含一个键,用于查询该键是否存在 map和set中的键(key)仅允许出现一次 multimap,支持同一个键多次出现的map multiset,支持同一个键多次出现的set,北京邮电大学,Map类型,头文件 #include 命名空间:using namespace std; 使用 map wordCount; 键类型的约束 键类型必须定义操

29、作符,而且该操作符必须能“正确地工作”,即满足语义 这是唯一的约束,不要求支持其他关系或相等运算,北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名空间 异常处理,北京邮电大学,泛型算法(generic algorithm),注:接续容器类的内容 标准库中,容器类定义的操作很少 定义了:添加、删除、访问元素、获取容器大小、获取迭代器等 另外通过一组算法来提供功能 例如,排序,查找特定元素,查找最大/最小元素等 算法大都不依赖特定的容器类型 即,“泛型”的 可作用于不同类型的容器,和不同类型的元素 自定义的类型只要与标准库兼容,也可以使用这些泛型算法 标准库中定义了超过100

30、种算法,北京邮电大学,Find()举例,举例,在vector对象中查找特定值 vector:const_iterator res = find(vec.begin(), vec.end(), value); if (res = vec.end() / 相等表示没找到 else / 不等则表示找到,res指向该元素 调用时传入两个迭代器,和一个值 找到,则返回指向该元素的迭代器对象 没找到,则返回第二个迭代器实参,北京邮电大学,Find()举例,工作流程 从第1个迭代器开始,顺序检查每个元素 如果当前元素等于要查找的值,则返回指向该元素的迭代器 否则,检查下一个元素,重复步骤2,直到找到这个值,

31、或者检查完所有的元素(到达第2个迭代器) 如果已经到达集合末尾,而且还未找到该值,则返回第2个迭代器,指明要查找的值在集合中不存在,北京邮电大学,Find()举例,标准算法的特点:独立于具体类型 Find()使用迭代器,与容器的类型无关 这个算法有一点隐式地依赖元素类型 必须能够对元素做比较运算 Find算法的要求 需要某种遍历集合的方式:能够从一个元素移到下一个元素 必须能够知道是否到达了集合末尾 必须能够对容器中的每个元素与被查找的元素进行比较 需要能够指出元素在容器中的位置,或表示没找到 迭代器的作用:实现遍历容器的功能 所有迭代器都支持自增操作(+),可以从一个元素定位到下一个元素,北

32、京邮电大学,泛型算法,头文件 泛型算法:#include 数值计算:#include 算法分类,按对容器的操作方式 只读算法 写容器元素的算法 对容器元素进行重排序的算法,北京邮电大学,只读算法,读取某个范围内的元素,但不会写这些元素 例如,find() 又如,accumulate(),求和运算,北京邮电大学,写容器元素的算法,算法需要写入元素值 需要确保算法所写的序列能够存储待写元素 写入输入序列的元素 如,fill(vec.begin(), vec.end(), value); /全部填为value 不检查写入操作的算法 如,fill_n(vec.begin(), length, valu

33、e); /填length个数据 写入到目标迭代器的算法 如,copy(ilist.begin(), ilist.end(), ivec.begin(); /从ilist拷贝到ivec,北京邮电大学,对容器元素进行重排序的算法,排序算法 例如,字符串按长度排序 sort(svec.begin(), svec.end(); stable_sort(svec.begin(), svec.end(), isShorter); bool isShorter( const string ,北京邮电大学,模板分类,函数模板 独立于类型的函数,可作为一种方式,产生函数的特定类型版本 例如,泛型算法find()

34、 类模板 与函数模板类似,但应用于类(class) 例如,容器类vector和list,北京邮电大学,函数模板的初衷,举例,比较两个输入值 int compare( const string ,北京邮电大学,代码非常类似,仅数据类型不同,函数模板的定义,基于函数模板的compare函数实现 template int compare( const T 模板形参表:尖括号内的部分 可以有一个或多个模板形参,形参之间以逗号分隔 模板形参表不能为空,北京邮电大学,模板形参表,模板形参表,形式上很像函数形参表 函数形参表,定义了特定类型的局部变量,但不初始化变量,由运行时提供的实参来初始化 模板形参表,

35、定义了可以在类或函数中使用的类型或值,由编译时制定的具体类型来替换 可以是表示类型的类型形参,也可以是表示常量表达式的非类型形参 类型形参在关键字class或typename之后定义 Class和typename没有区别,北京邮电大学,使用函数模板,举例,Compare函数的用法 cout compare( 1, 2) endl; / T在这里是int string s1 = “hello”, s2 = “world”; cout compare(s1, s2) endl; /T在这里是string 编译器将推断用哪个(或哪些)模板实参绑定到模板形参 确定实际的模板实参的过程,称为编译器实例化

36、了函数模板的一个实例 实际上,编译器推导出实际模板实参后,将产生并编译该版本的函数 多次使用同一类型,只会产生一个函数实例,北京邮电大学,Inline函数模板,函数模板也可以声明为inline inline放在:模板参数表之后、返回类型之前,不能放在template之前 例如,compare函数 template inline T compare( const T,北京邮电大学,定义类模板,类模板也是模板,定义和使用与函数模板类似 必须以template关键字开头 后面接模板形参表 例如,我们自己实现的vector template class MyVector public: Queue()

37、; T,北京邮电大学,使用类模板,例如,以MyVector为例 MyVector vi; MyVector vvd; MyVector vs;,北京邮电大学,这里有个空格,模板形参,模板形参的名字没有本质含义 与函数形参类似 Compare函数中命名为T,也可以是任意名字 模板形参作用域 从声明为模板形参之后,直到模板声明或定义的末尾处 遵循名字屏蔽规则 即模板形参将屏蔽同名的全局名字 用作模板形参的名字,不能在模板内部重用 即只能使用一次,北京邮电大学,模板形参作用域举例,例如, typedef double T; template T calc( const T ,北京邮电大学,泛型编程的

38、概念,泛型编程(Generic Programming,GP) 独立于任何特定类型的编码方式 使用时,再提供具体程序实例所操作的类型和值 例如:标准库中的容器类、迭代器和算法 Vector只有一个实现,但可用于多种数据类型 模板 泛型编程的基础,北京邮电大学,泛型编程 vs. 面向对象编程,相同点:两者都依赖于某种形式的多态性 不同点:多态性的表现方式不同 面向对象编程:运行时(Runtime)多态性 在程序执行时,应用于存在继承关系的类 执行时,可以忽略基类和派生类之间的类型差异 泛型编程:编译时多态性,或参数式多态性 编译时,用于跨越不相关的类型 例如,vector的设计者不用了解我们设计

39、的类,北京邮电大学,泛型编程回顾,优点 一次编写,处处使用 另一种意义上的多态 容易使用,易于理解 缺点 安全性、知识产权保护、系统集成等方面存在问题 源代码必须定义在头文件中 难以调试和测试,易用但难以开发 增加了程序体积,存在一定代价 针对每种具体数据类型生成单独的执行代码,北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名空间 异常处理,北京邮电大学,命名空间,给定作用域内,每个名字都应该是唯一的 庞大、复杂的程序,容易出现冲突 模板名、类型名、函数名难免冲突, “命名空间污染”问题 曾经的解决方案 取很长的命名 例如,my_space_foo,my_space_ba

40、r, 加特殊字符作为前缀 _my_foo(一个下划线的前缀) _my_bar(两个下划线的前缀) 问题:难以记忆,难以使用,北京邮电大学,命名空间的定义,关键字:namespace,接命名空间的名字 namespace my_space class Complex ; Complex operator+ ( ) 命名空间的名字在所处的作用域内必须唯一 可以在全局作用域或其他作用域内部定义 不能在函数或类内部定义 命名空间作用域不能以分号结束,北京邮电大学,命名空间,每个命名空间是一个作用域 命名空间成员:命名空间内的实体 命名空间内,每个名字必须对应唯一实体 不同命名空间引入了不同的作用域 不

41、同命名空间内可以具有同名成员,北京邮电大学,从外部来访问命名空间成员(1),使用空间名来访问 my_space:Complex c1 = my_space:Complex(1,2); c1.display(cout); 特点 仅引用处有效,使用较为麻烦 作用域小,不会影响当前范围内的命名空间 适用情况 使用空间成员的次数很少 不希望污染当前的命名空间,北京邮电大学,从外部来访问命名空间成员(2),引入指定的命名空间成员 Using关键字 using my_space:Complex; Complex c2 = Complex( 3, 4 ); c2.display( cout ); 特点 只引

42、入指定的成员,不会污染当前命名空间 适用情况 仅需要少数的成员 不希望污染当前命名空间,北京邮电大学,从外部来访问命名空间成员(3),引入整个命名空间 Using和namespace using namespace my_space; Complex c2 = Complex( 3, 4 ); c2.display( cout ); 特点 一次性将整个命名空间引入 适用情况 通常采用这种方式,使用最方便 但可能导致命名空间污染,北京邮电大学,命名空间的连续性,命名空间可以是不连续的! 同一个命名空间,即名字相同 可以分散在几个部分中定义 甚至可以分散在不同文件中 所有分离的部分,合起来构成该命

43、名空间 命名空间的定义是累加的,北京邮电大学,全局命名空间,全局作用域中的名字组成全局命名空间 全局命名空间是隐式声明的 存在于每个程序中 全局命名空间没有名字 直接用“:”引用全局命名空间实体 例如,:member_name,北京邮电大学,嵌套命名空间,嵌套命名空间 一个命名空间中包含另一个命名空间 作用域也是嵌套的 可以用来改进代码的组织结构 namespace hello namespace world class Complex ; hello:world:Complex c3 = ;,北京邮电大学,无名命名空间,命名空间可以没有名字 特殊的命名空间 其中的实体仅局部于定义的文件中,无

44、法跨越文件访问 每个文件有自己的“无名命名空间” 可以在给定文件中不连续,但不能跨越文件 可以直接访问其中的实体 适用情况 目的是保持代码的局部性 用来替代文件中的静态声明,北京邮电大学,目录,函数重载 运算符重载 容器类 泛型算法和模板 命名空间 异常处理,北京邮电大学,异常处理,大规模应用程序 更严格的正常运转时间 更健壮的错误检测和错误处理 错误处理经常必须跨越独立开发的多个子系统 这就需要异常处理 使用异常处理,独立开发的模块能够针对执行中出现的问题相互通信,并处理这些问题 问题的检测和解决是分离的,因此问题检测部分可以不必了解如何处理问题 例如,底层模块遇到问题,由高层模块来处理,北

45、京邮电大学,异常处理,异常处理机制 检测部分,抛出一个对象(即异常) 处理部分,捕获并分析这个对象 对象的类型和内容,就成为两者的通信方式,北京邮电大学,异常处理的语法组成,Throw表达式 错误检测部分使用,说明遇到了不可处理的错误,即引发(raise)了异常条件 Try块(try block) 错误处理部分使用,用来处理异常 以try关键字开始,并以一个或多个catch子句结束 Try块中抛出的异常,通常会被其中一个catch子句处理 异常类(exception class) 用来在throw和try块之间传递有关的错误信息 不限于class,基本类型也可以,北京邮电大学,Throw表达式,使用方法:throw 对象/数据等 例如,除法运算的参数检查 int divide(int d1, int d2) / 无异常处理版本 if (d2 = 0) return -1; /问题,返回值碰巧是-1怎么办? else return d1 / d2; int divide(

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论