C++ primer 摘要《局部类、嵌套类、类域》20090127

来源:互联网 发布:excel表格工资表数据 编辑:程序博客网 时间:2024/04/30 06:56

===13.6.2 使用指向类成员的指针===
int (Screen::*pmfi)() = &Screen::height;
Screen& (Screen::*pmfS)( const Screen& ) = &Screen::copy;
Screen myScreen, *bufScreen;
// 直接调用成员函数
if ( myScreen.height() == bufScreen->height() )
    bufScreen->copy( myScreen );
// 通过成员指针的等价调用
if ( (myScreen.*pmfi)() == (bufScreen->*pmfi)() )
    (bufScreen->*pmfS)( myScreen );//注意加括弧
类似地指向数据成员的指针可以按下列方式被访问
typedef short Screen::*ps_Screen;
Screen myScreen, *tmpScreen = new Screen( 10, 10 );
ps_Screen pH = &Screen::_height;
ps_Screen pW = &Screen::_width;
tmpScreen->*pH = myScreen.*pH;
tmpScreen->*pW = myScreen.*pW;
===13.6.3 静态类成员的指针===
静态类成员是属于该类的全局对象和函数它们的指针是普通指针(记住:静态成员函数没有this 指针)
class Account {
public:
    static void raiseInterest( double incr );
    static double interest() { return _interestRate; }
    double amount() { return _amount; }
private:
    static double _interestRate;
    double _amount;
    string _owner;
};
&_interestRate 的类型是double* 而不是
// 不是 &_interestRate 的类型
double Account::*
1.静态数据成员
指向_interestRate 的指针定义如下
// OK: 是 double*, 而不是 double Account::*
double *pd = &Account::_interestRate;
它被解引用的方式与普通指针一样不需要相关的类对象
2.静态成员函数
// ok: douple(*pf) () 不是 double(Account::*pf)()
double (*pf)() = &Account::interest;

===13.7 联合一种节省空间的类===
union 不能有静态数据成员或是引用成员如果一个类类型定义了构造函数析构函数
或拷贝赋值操作符则它不能成为union 的成员类型例如
union illegal_members {
    Screen s; // 错误: 有构造函数
    Screen *ps; // ok
    static int is; // 错误: 静态成员
    int &rfi; // 错误: 引用成员
};
===13.8 位域bit-field 一种节省空间的成员===
有一种被称为位域bit-field 的特殊的类数据成员,它可以被声明用来存放特定数目的位
位域必须是有序数据类型
===13.9 类域===
在类定义中用到的名字必须在使用前首先被声明,这个规则有两种例外的情况
第一个例外是对于被用在inline 成员函数定义中的名字,第二个例外是于被用作缺省实参的名字
1.对于用在inline 成员函数定义中的名字的解析有两步
  a.首先函数声明即函数返回类型和参数表在其所在的类定义中出现的位置被处理
  b.然后函数体在完整的类域中被处理——所有的成员的声明都被看到
  class String {
  public:
      typedef int index_type;
      char& operator[] ( index_type elem )//index_type在第一步中检查
      {return _string[ elem ]; }//_string在第二步中检查
  private:
      char * _string;
  };
2.缺省实参也是在名字解析的第二步:在完整的类域中被处理
class Screen {
public:
    // bkground 指向在类定义中后来声明的静态成员
    Screen& clear( char = bkground );
private:
    static const char bkground = '#';
};
尽管在成员函数声明中的缺省实参是在类的完整域中被解析的,但是如果缺省实参引用
了一个非静态成员,则程序仍然是错的。
因为非静态数据成员在它的值被程序使用之前,必须先被绑定到该类类型的对象上,或绑定到指向该类类型的对象的指针上
class Screen {
public:
    // ...
    // 错误: bkground 是一个非 static 成员
    Screen& clear( char = bkground );
private:
    const char bkground;
};
//
class Account {
    typedef double Money;
    // ...
private:
    static Money _interestRate;
    static Money initInterest();
};
// Money 必须用 Account:: 限定修饰,因为Money在类域外
Account::Money Account::_interestRate = initInterest();
===13.9.1 类域中的名字解析===
用在类定义中的名字其解析过程如下
1. 在名字使用之前出现的类成员的声明应予以考虑
2. 如果步骤1 的解析没有成功,则在类定义之前的名字空间域中出现的声明应予以考虑
被用在类成员函数定义中的名字的解析过程如下
1. 在成员函数局部域中的声明首先被考虑
2. 如果在步骤1 中的解析不成功,则考虑所有的类成员声明
3. 如果在步骤2 中的解析不成功,则考虑在成员函数定义之前的名字空间域中出现的声明

===13.10 嵌套类===
1.嵌套类不能直接访问其外围类的非静态成员,即使这些成员是公有的
任何对外围类的非静态成员的访问,都要求通过外围类的指针引用或对象来完成
例如
class List {
public:
    int init( int );
private:
    class ListItem {
    public:
        ListItem( int val = 0 );
        void mf( const List & );
        int value;
        int memb;
    };
};
List::ListItem::ListItem( int val )
{
    // List::init() 是类 List 的非静态成员
    // 必须通过 List 类型的对象或指针来使用
    value = init( val ); // 错误: 非法使用 init
}
2.嵌套类可以直接访问外围类的静态成员/类型名/枚举值(假定这些成员是公有的)
class List {
public:
    typedef int (*pFunc)();
    enum ListStatus { Good, Empty, Corrupted };
    // ...
private:
    class ListItem {
    public:
        void check_status();
        ListStatus status; // ok
        pFunc action; // ok
        // ...
    };
    // ...
};
===13.12 局部类===
类也可以定义在函数体内这样的类被称为局部类local class
不允许局部类声明静态数据成员
局部类只能访问在外围局部域中定义的类型名、静态变量以及枚举值
int a, val;
void foo( int val )
{
    static int si;
    enum Loc { a = 1024, b };
    class Bar {
    public:
        Loc locVal; // ok;
        int barVal;
        void fooBar( Loc l = a ) { // ok: Loc::a
            barVal = val; // 错误: 局部对象
            barVal = ::val; // OK: 全局对象
            barVal = si; // ok: 静态局部对象
            locVal = b; // ok: 枚举值
        }
    };
    // ...
}