C++ Primer Plus (6th) Chap15 友元、异常和其他 摘录

15.1 友元

类并非只能拥有友元函数,也可以将类作为友元。

15.1.1 友元类

友元类可以位于公有、私有或保护部分,其所在位置无关紧要。友元类的成员函数与全局函数能访问该类的私有成员。

class TV
{
public:
    friend class Remote;
...
};

15.1.2 友元成员函数

若只需要类中某一个或两个函数访问另一个类的私有成员,则只需将此类函数设置为另一个的友元函数。

class TV
{
    friend void Remote::set_chan(TV& t, int c);
...
};

然而,要使编译器能够处理上述语句,它必须知道Remote的定义。否则,它无法知道Remote是一个类,而set_chan是这个类的方法。这意味着应将Remote的定义放在Tv的定义前面。Remote的方法提到了TV对象,而这意味着TV定义应当位于Remote定义前面。避开这种循环依赖的方法是,使用前向声明(forward declaration)。代码如下:

class Tv;            // forward declaration
class Remote {...};  // definition
class Tv {...};      // definition

内联函数的链接性是内部的,意味着函数定义必须在使用函数的文件中。即将内联函数定义与函数声明放在同一个文件中。

15.1.3 其他友元关系

若让类成为彼此的友元。需要记住一点,对于使用Remote对象的Tv方法,其原型可在Remote类声明之前声明,但必须在Remote类声明之后定义,以便编译器有足够的信息来编译方法。

class Tv
{
friend class Remote;
public:
    void buzz(Remote& r); 
...
};

class Remote
{
friend class Tv;
public:
    void volup(Tv& t){...};
...
};

inline void Tv::buzz(Remote& r)
{
...
}

有Remote的声明位于Tv声明的后面,所以可以咋类声明中定义Remote::volup(),但在Tv::buzz()方法必须在Tv声明的外部定义,使其位于Remote声明的后面。

15.1.4 共同的友元

需要使用友元的另一种情况是,函数需要访问两个类的私有数据。

class Analyzer;
class Probe
{
friend void sync(Analyzer& a, const Probe& p);
friend void sync(const Probe& p, Analyzer& a);
...
};

class Analyzer
{
friend void sync(Analyzer& a, const Probe& p);
friend void sync(const Probe& p, Analyzer& a);
...
};

inline void sync(Analyzer& a, const Probe& p)
{
...
}

inline void sync(const Probe& p, Analyzer& a)
{
...
}

15.2 嵌套类

在C++中,可以将类声明放在另一个类。在另一个类中声明的类被称为嵌套类(nested class),它通过提供新的类型类作用域来避免名称混乱。包含类的成员函数可以创建和使用被嵌套类的对象;而仅当声明位于公有部分,才能在包含类的外面使用嵌套类,而且必须使用作用域解析符。

对类嵌套和包含不一样。包含意味着将类对象作为另一个类的成员,而对类进行嵌套不创建类成员,而是定义了一种类型,该类型仅在包含嵌套类声明的类中有效。

class Queue
{
private:
    // nested struct
    struct Node
    {
        Item item;
        Node* next;
    };
...
};

15.2.1 嵌套类的访问权限

声明位置包含它的类包含它的类的派生类外部
私有部分
保护部分
公有部分

15.3 异常

15.3.3 异常机制

引发异常;

使用处理程序捕获异常;

使用try块。

// error4.cpp - using exception classes
#include<iostream>
#include<cmath>

class bad_hmean
{
private:
    double v1;
    double v2;
public:
    bad_hmean(double a = 0, double b = 0) : v1(a), v2(b) {}
    void mesg();

};

inline void bad_hmean::mesg()
{
    std::cout << "hmean(" << v1 << "," << v2 << "):" << "invalid";
}



// function prototype
double hmean(double a, double b)
{
    if (a == -b)
        throw bad_hmean(a, b); // 抛出异常
    return 2.0 * a * b / (a + b);
}

int main()
{
    using std::cout;
    using std::cin;
    using std::endl;

    double x, y, z;
    cout << "Enter two numbers";
    while (cin >> x >> y)
    {
        try // 将测试代码放入try代码块中
        {
            z = hmean(x, y);
            cout << "Harmonic mean of " << x << " and " << y << " is " << z << endl;
        }
        catch (bad_hmean& bg) // 根据throw抛出对象的类型接收
        {
            bh.mesg();
            cout << "Try again";
            continue;
        }
    }
    return 0;
}

15.3.8 exception类

logic_error:

        domain_error: 定义域或值域取值范围超过。例如sin函数之类

        invalid_argument:给函数传递意料外的参数

        length_error:没有足够的空间来执行所需操作。例如字符拼接时

        out_of_bounds:索引越界

runtime_error:

        range_over:计算结果不在函数允许的范围之内,但没有发生上溢或下溢;

        overflow_error:比类型可表示范围的最大数值还大;

        underflow_error:比类型可表示范围的最小数值还大;

15.4 RTTI(Runtime Type Identification)

dynamic_cast运算符用于将派生类指针转换为基类指针,其主要用途确保安全地调用虚函数。

dynamic_cast<Base*>(Derived*);

const_cast运算符改变值为const或volatile,提供该运算符的原因是,有时候可能需要这样一个值,它在大多数时候是常量,而有时又是可以修改的。

class High {...};
High bar;
const High* pbar = &bar;
High* pb = const_cast<High*>(pbar);

static_cast用法是,仅当type_name可被隐式转换为expression所属的类型或expression可被隐式的转换为type_name所属类型时,下述转换才合法。

static_cast<type-name>(expression);

reinterpret_cast运算符用于天生危险的类型转换。依赖于底层编程技术,是不可移植的。

Typied运算符返回一个type_info对象。可以对两个typied的返回值进行比较,以确保对象是否为特定类型。

typied(pt1) == typied(pt2);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值