个人觉得学习编程最有效的方法是阅读专业的书籍,通过阅读专业书籍可以构建更加系统化的知识体系。
一直以来都很想深入学习一下C++,将其作为自己的主力开发语言。现在为了完成自己这一直以来的心愿,准备认真学习《C++ Primer Plus》。
为了提高学习效率,在学习的过程中将通过发布学习笔记的方式,持续记录自己学习C++的过程。
友元声明可以位于公有、私有或保护部分,位置无关紧要。
通过如下代码,可以将Remote
类声明为Tv
类的友元类:
class Tv
{
friend class Remote;
...
}
class Remote
{
...
}
让Remote::set_chan()
称为Tv
类的友元的方法是,在Tv
类声明中将其声明为友元:
class Tv
{
friend void Remote::set_chan(Tv & t, int c);
...
}
为了解决定义位置循环依赖的问题,需要使用向前声明(forward declaration)。为此需要这样进行排列:
class Tv;//向前声明
class Remote{...};
class Tv{...};
让类彼此成为对方的友元来实现。
函数需要访问两个类的私有数据时。
在另一个类中声明的类被称为嵌套类(nested class),它通过提供新的类型类作用与来避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能在包含类的外面使用嵌套类,而且必须使用作用域解析运算符。
嵌套类、结构和枚举的作用域特征:
声明位置 | 包含它的类是否可以使用它 | 从包含它的类派生而来的类是否可以使用它 | 在外部是否可以使用 |
---|---|---|---|
私有部分 | 是 | 否 | 否 |
保护部分 | 是 | 是 | 否 |
公有部分 | 是 | 是 | 是,通过类限定符来使用 |
对嵌套类的访问控制权的控制规则与常规类相同。
将类定义转换为模板时,不会由于它包含嵌套类带来问题。
(1) 调用abort()
abort()
函数的原型位于头文件cstdlib
(或stdlib.h
)中,其典型实现是向标准错误流(即cerr
使用的错误流)发送消息abnomal program termination
(程序异常终止),然后终止程序。它还返回一个随实现而异的值,告诉操作系统(或父级进程),处理失败。
(2)返回错误码
一种比异常终止更灵活的方法是,使用函数的返回值来指出问题。
(3)异常机制
C++异常时对程序运行过程中发生的异常情况的一种响应。异常提供了将控制权从程序的一个部分传递到另一个部分的途径。对异常的处理由3个部分组成:
try
块。throw
关键字表示引发异常,紧随其后的值(例如字符串和对象)指出了异常的特征。
catch
关键字表示捕获异常。
try
块标识其中特定的异常可能被激活的代码块,它后面跟一个或多个catch
块。
try{
uint z = 1 - 2;
}
catch
{
std::cout << "计算结果超出范围" <<std::endl;
}
执行throw
语句类似于执行返回语句,因为它也将终止函数的执行;但不是将控制权返回给调用程序,而是导致程序沿函数调用序列后退,直到找到包含try
块的函数。
(4)将对象用作异常类型
通常,引发异常的函数将传递一个对象。这样做得重要优点之一是,可以使用不同的异常类型来区分不同的函数在不同情况下引发的异常。另外,对象可以携带信息,程序员可以根据这些信息来确定引发异常的原因。同时,catch
块可以根据这些信息来决定采取什么措施。
(5) 异常规范和C++11
C++98新增,C++11已摒弃。
(6)栈解退
假设try
块设有直接调用引发异常的函数,而是调用了对引发异常的函数进行调用的函数,则程序流程将从引发异常的函数跳到包含try
块和处理程序的函数。这涉及到栈解退(unwinding the stack)。
(7)其他异常特性
引发异常时编译器总是创建一个临时拷贝,即使异常规范和catch
块中指定的是引用。
基类引用可以执行派生类对象。
应将捕获位于层次结构最下面的异常类的catch
语句放在最前面,将捕获基类异常的catch
语句放在最后面。
使用省略号来表示异常类型,从而捕获任何异常:
catch(…)
{
//statements
}
在catch
语句中使用基类对象时,将捕获所有的派生类对象,但派生特性将被剥去,因此将使用虚方法的基类版本。
(8)exception
类
exception
头文件(以前为exception.h
或except.h
)定义了exception
类,C++可以把它用作其他异常类的基类。
C++提供了一种在失败时返回空指针的new
:
int * pi = new (std::nothrow) int;
(9)异常、类和继承
异常、类和继承以三种方式相互关联。首先,可以像标准C++库所做的那样,从一个异常类派生出另个一个;其次,可以在类定义中嵌套异常类声明来组合异常;最后,这种嵌套声明本身可被继承,还可用作基类。
(10) 异常何时会迷失方向
虽然C++11摒弃了异常规范,但仍支持它,且有些现有的代码使用了它。
(11)有关异常的注意事项
使用异常会增加程序代码,降低程序的运行速度。异常规范不适用于模板,因为模板函数引发的异常可能随特定的具体化而异。异常和动态内存分配并非总能协同工作。
RTTI是运行阶段类型识别(Runtime Type Identification)的简称。这是新添加到C++中的特性之一,很多老式实现不支持。
C++有3个支持RTTI的元素。
dynamic_cast
运算符将使用一个指向基类的指针来生成一个指向派生类的指针;否则,该运算符返回0——空指针。typeid
运算符返回一个指出对象的类型的值。type_info
结构存储了有关特定类型的信息。Superb * pm = dynamic_cast<Superb *>(pg);
类型转换运算符:
dynamic_cast
const_cast
static_cast
reinterpret_cast