1.异常处理:
异常处理机制允许程序中独立开发的部分能够在运行时就出现的问题,进行通信并作出相应处理。
当执行一个throw时,跟在throw后面的语句将不再被执行(类似return)。程序的控制权从throw转移到与之匹配的catch模块。
栈展开:当throw出现在一个try语句块内中,寻找与此try关联的catch语句。找不到的话就到外层的try中找。如果找不到匹配的catch,则程序调用标准库函数terminate来终止程序的执行过程。
异常对象是一种特殊的对象,编译器使用异常抛出表达式来对异常对象进行拷贝初始化。因此,throw语句中的表达式必须拥有完整类型(表达式是类类型的话,则相应的类必须有一个可访问的析构函数和拷贝或移动构造函数。如果该表达式是宿主类型或函数类型,则表达式将被转换成与之对应的指针类型)。
异常对象位于由编译器管理的空间中,编译器确保无论最终调用哪个catch子句都能访问该空间。当异常处理完毕后,异常对象被销毁。
当我们抛出一条表达式时,该表达式的静态编译时类型决定了异常对象的类型。
catch子句中的异常声明看起来像只包含一个形参的函数形参列表。
如果参数是引用类型,则改变参数就是改变异常对象。
重新抛出:是将异常传递给更上一层的catch语句。一条throw语句,不包含任何表达式。
空的throw语句只能出现在catch语句或catch语句直接或间接调用的函数之内,如果在代码之外的区域遇到空throw语句,编译器将调用terminate。
一个重新抛出语句并不指定新的表达式,而是将当前的异常对象沿着调用链向上传递。
捕获所有异常: catch(…);
处理构造函数初始值异常的唯一方法,是将构造函数写成函数try语句块。函数try语句话只能处理构造函数开始执行后发生的异常。
关键字try出现在表示构造函数初始值列表的冒号以及表示构造函数体的花括号之间。
C++新标准中的noexcept说明符:指定某个函数不会抛出异常。关键字noexcept紧跟站函数参数列表后面。
一个函数有noexcept说明也可以还有throw语句或调用可能抛出异常的其他函数。一旦一个know except函数抛出了异常函数就会调用terminate以确保遵守不再运行时抛出异常的承诺。
No,except说明符接受一个可选的实参,该食餐能够转换成bool类型。如果实参是tue,则函数不会抛出异常,如果实参是false,则函数可能抛出异常。
noexcept运算符是一个一元运算符。
noexcept(e);
当e调用的所有函数都做了不抛出说明。且e本身不含有throw语句时,表达式为true,否则,noexcept(e)返回false。
void f() noexcept (noexcept (g ()); // f和g的异常处理说明一致
函数指针及该指针所指向的函数必须具有一致的异常说明。
如果一个虚函数承诺不会抛出异常,值得派生类出来的虚函数也必须做出同样的承诺。如果基类的虚函数允许抛出异常,则派生类对应的函数可抛可不抛。
2.命名空间:
命名空间:为防止名字冲突提供了更加可控的机制。命名空间分割了全局命名空间,其中每个命名空间是一个作用域。
关键字namespace + 命名空间的名字 后面是由花括号括起来的声明和定义。
每个命名空间都是一个作用域。
命名空间可以不是连续的。
通常不把#include放在命名空间内部。如果放在内部了,则意味着把头文件中所有的名字定义成该命名空间的成员。
可以在全局作用域或该命名空间内的,定义成员,但是不能在一个不相关的作用域中定义。
模板特例化必须声明成std的成员
全局命名空间:全局命名空间以隐式的方式声明,并且在所有程序都存在。形如 ::member_name;
允许嵌套命名空间。最内层的名字与外层冲突,内层的名字有效。
外部使用形如 外层命名空间名::内层命名空间名::member_name;
C++11新标准引入一种新的嵌套命名空间,称为内联命名空间。
inline namespace nameA{ } // 只需要在第一次定义命名空间时指定是否是inline的
如果nameA嵌套在命名空间nameB内,外部调用nameB::member_name即可使用nameA中成员。
未命名命名空间:指namespace后紧跟花括号括起来的一系列声明语句。其中定义的变量拥有静态生命周期:第一次使用前创建,直到程序结束才销毁。
未命名的命名空间可以在某个给定的文件内不连续,但是不能跨越多个文件。如果两个文件都还有未命名的命名空间,则这两个空间互相无关。未命名的命名空间仅在特定的文件内部有效,作用范围不会横跨多个不同的文件。
命名空间别名: namespace othername = nameA::nameB;
using声明语句一次只引用命名空间的一个成员。有效范围从using声明的地方,一直到using声明所在的作用域结束为止。
using指示以关键字using开始,后面是关键字namespace以及命名空间的名字。
这样使得某个特定的命名空间中所有的名字都可见,我们就无需为他们添加任何前缀限定符了。简写的名字从哟经只是开始一直到哟经只是所在的作用域结束都能使用。
如果提供了一个对std等命名空间的using指示。而未做任何特殊控制的话,将重新引入由于使用了多个库而造成的名字冲突问题。
using指示一般被看作是出现在最近的外层作用域中。
头文件如果在其顶层作用域中含有using指示或using声明,则会将名字注入到所有包含该头文件的文件中。
在命名空间本身的实现文件中就可以使用using指示。
给函数传递一个类类型的对象时,除了在常规的作用域查找外,还会查找实参类所属的命名空间。
使用std::move和std::forward使用std前缀。因为容易引起冲突。
using声明语句声明的是一个名字,而非一个特定的函数。当我们为函数书写using声明时,该函数的所有版本都被引入到当前作用域中。
一个using声明引入的函数,将重载该声明语句所属作用域中,已有的其他同名函数。
与using声明不同,using指示引入一个已有函数形参列表完全相同的函数,并不会产生错误。
如果存在多个using指示,则来自每个命名空间的名字,都会成为候选函数集的一部分。
3.多重继承与虚继承:
多重继承:从多个直接基类中产生派生类的能力。多重继承的派生类继承了所有父类的属性。
派生类的构造函数初始值列表将实参分别传递给每个直接基类,其中基类的构造顺序与派生列表中的基类出现顺序保持一致。
类作用域:在只有一个基类的情况,查找过程沿着继承体系自底向上进行。派生类会隐藏基类的同名成员。在多重继承情况下,查找在所有基类同时进行,如果名字在多个基类被找到,则该名字的使用具有二义性。
尽管在派生列表中同一个基类只能出现一次,但实际上派生类可以多次继承同一个类(间接基类)。
如果某个类在派生过程中出现了多次,则派生类中将包含该类的多个子对象。
可以通过虚继承,承诺愿意共享它的基类。在这种机制下,不论虚基类在继承体系中出现多少次?在派生类中都只包含唯一一个共享的虚基类子对象。
class baseA : public virtual baseTotal{}
class baseB : public virtual baseTotal{}
class classC : public baseA, public baseB{}
classC就只含有一个baseTotal子对象了。
虚基类由最底层的派生类初始化。
在继承体系中,每个类都可能在某一时刻成为最底层的派生类,所以派生类的构造函数就必须初始化它的虚基类。
含有虚函数的对象构造顺序:首先初始化虚基类子部分,再按照基类在派生类的次序进行初始化。一个类有多个虚基类时,按照他们在派生列表中出现的次序从左到右依次构造。
本文详细介绍了C++中的异常处理机制,包括异常抛出、捕获、重新抛出及noexcept说明符的使用。同时,深入探讨了命名空间的概念,如何避免名字冲突,以及多重继承与虚继承的特点。
1420

被折叠的 条评论
为什么被折叠?



