===13.3.5 const 和volatile 成员函数===
const成员函数
1.只有被声明为const 的成员函数才能被一个const 类对象调用
const类对象不能调用非const成员函数(除构造函数析构函数外)
2.对于在类体之外定义的const 成员函数,我们必须在它的定义和声明中同时指定关键字const
class Screen {
public:
bool isEqual( char ch ) const;
// ...
private:
string::size_type _cursor;
string _screen;
// ...
};
bool Screen::isEqual( char ch ) const
{
return ch == _screen[_cursor];
}
3.把一个修改类数据成员的函数声明为const 是非法的
void error( int ival ) const { _cursor = ival; }
4.把一个成员函数声明为const 可以保证这个成员函数不修改类的数据成员
但是,如果该类含有指针,那么在const 成员函数中就能修改指针所指的对象
class Text {
public:
void bad( const string &parm ) const;
private:
char *_text;//指针
};
void Text::bad( const string &parm ) const
{
_text = parm.c_str(); // 错误: 不能修改 _text
for ( int ix = 0; ix < parm.size(); ++ix )
_text[ix] = parm[ix]; // 不好的风格, 但不是错误的
}
5.const 成员函数可以被相同参数表的非const 成员函数重载例
class Screen {
public:
char get(int x, int y);
char get(int x, int y) const;
// ...
};
int main() {
const Screen cs;
Screen s;
char ch = cs.get(0,0); // 调用 const 成员
ch = s.get(0,0); // 调用非 const 成员
}
6.构造函数和析构函数是两个例外,即使构造函数和析构函数不是const 成员函数,const类对象也可以调用它们
当构造函数执行结束,类对象已经被初始化时类对象的常量性就
被建立起来了,析构函数一被调用常量性就消失,所以一个const 类对象从构造完成时
刻到析构开始时刻这段时间内被认为是const
7.与const 类对象类似,对于一个volatile 类对象,只有volatile成员函数构造函数和析构函数可以被调用
8.mutable数据成员功能:const成员函数可以修改mutable数据成员
===13.5 静态类成员===
作为特例***有序型***的const 静态数据成员可以在类体中用一常量值初始化
在类体内初始化一个const 静态数据成员时,该成员必须仍然要被定义在类定义之外
因为这个静态数据成员的初始值是在类体中指定的,所以在类定义之外的定义不能指定初始值
// 头文件
class Account {
// ...
private:
static const int nameSize = 16;//有序型
static const char name[nameSize];//非有序型
};
// 文本文件
const int Account::nameSize; // 必需的成员定义,能指定初始值
const char Account::name[nameSize] = "Savings Account";
静态数据成员的惟一性本质,使它能够以独特的方式被使用,这些方式对于非static 数据成员来说是非法的
1.静态数据成员的类型可以是其所属类
class Bar {
public:
// ...
private:
static Bar mem1; // ok
Bar *mem2; // ok
Bar mem3; // 错误
};
2.静态数据成员可以被作为类成员函数的缺省实参,而非static 成员不能
extern int var;
class Foo {
private:
int var;
static int stcvar;
public:
// 错误: 被解析为非 static 的 Foo::var
// 没有相关的类对象
int mem1( int = var );
// ok: 解析为 static 的 Foo::stcvar
// 无需相关的类对象
int mem2( int = stcvar );
// ok: int var 的全局实例
int mem3( int = ::var );
};
===13.5.1 静态成员函数===
1.静态成员函数的声明除了在类体中的函数声明前加上关键字static,以及不能声明为const 或volatile 之外,与非静态成员函数相同
2.出现在类体外的函数定义不能指定关键字static
3.静态成员函数没有this 指针,因此在静态成员函数中隐式或显式地引用这个指针都将导致编译时刻错误
试图访问隐式引用this 指针的非静态数据成员也会导致编译时刻错误
4.我们可以通过类对象或类指针访问静态成员函数,也可以用限定修饰名直接访问或调用静态成员函数而无需声明类对象
===13.6.1 类成员的类型===
函数指针不能被赋值为成员函数的地址
int (*pfi) ();
int HeightIs();//全局函数
pfi = HeightIs;//ok
inline int Screen::height() { return _height; }//成员函数
pfi = &Screen::height;// 非法赋值: 类型违例
指向成员函数的指针必须与向其赋值的函数类型匹配,不是两个而是三个方面都要匹配:1.参数的类型和个数2.返回类型3.它所属的类类型
数据成员指针和普通指针
普通指针含有引用一个对象所需的全部信息,数据成员指针在被用来访问数据成员之前必须先被绑定到一个对象或指针上.
定义一个成员函数指针需要指定函数返回类型参数表和类.例如,
指向Screen 成员函数并且能够引用成员函数height()和width()的指针类型如下
int (Screen::*) ()
// 所有指向类成员的指针都可以用0 赋值
int (Screen::*pmf1)() = 0;