51、static成员函数
因为static成员不是任何对象的组成部分,所以static成员函数不能被声明为const。毕竟,将成员函数声明为const就是承诺不会修改该函数所属的对象。最后,static成员函数也不能被声明为虚函数。
52、特殊的整型const static成员(P401)
const static数据成员在类的定义体中初始化时,该数据成员仍必须在类的定义体之外进行定义。
class Accout{
public:
static double rate() { return interestRate;}
static void rate(double); //sets a new rate
private:
static const int period = 30; //interest posted every 30 days
double daily_tbl[period]; // ok: period is constant expression
}
//definition of static member with no initializer;
//the initial value is specified inside the class definition
const int Accout::period;
但在gcc和MS vc++编译器下似乎均不需要再次定义,也就是题设的“必须”二字在此失效。
53、操作符重载(P435)
下面是一些指导原则,有助于决定将操作符设置为类成员还是普通非成员函数
- 赋值(=)、下标([])、调用(())和成员访问箭头(->)等操作符必须定义为成员,将这些操作符定义为非成员函数将在编译时标记为错误。
- 像赋值一样,复合赋值操作符通常应定义为类的成员。与赋值不同的是,不一定非得这样做,如果定义非成员复合赋值操作符,不会出现编译错误。
- 改变对象状态或与给定类型紧密联系的其他一些操作符,如自增、自减和解引用,通常应定义为类成员。
- 对称的操作符,如算术操作符、相等操作符、关系操作符和位操作符,最好定义为普通非成员函数。
54、区别操作符的前缀和后缀形式(P447)
同时定义前缀式操作符和后缀式操作符存在一个问题:它们的形参数目和类型相同,普通重载不能区别所定义的是前缀式操作符还是后缀式操作符。
为解决这一问题,后缀式操作符函数接受一个额外的(即,无用的)int型形参。使用后缀操作符时,编译器提供0作为这个形参的实参。尽管我们的前缀式操作符函数可以使用这个额外的形参,但通常不应该这样做。那个形参不是后缀式操作符的正常工作所需要的,它的唯一目的是使后缀函数与前缀函数区别开来。
55、显式调用前缀式操作符
CheckedPtr parr(ia, ia+size); //ia points to an array of ints
parr.operator(0); //call postfix operator++
parr.operator(); //call prefix operator++
56、函数对象(P450)
struct absInt {
int operator() (int val){
return val<0 ? –val : val;
}
};
int i = –42;
absInt absObj; //object that defines function call operator
unsigned int ui = absObj(i); //calls absInt::operator(int)
尽管absObj是一个对象而不是函数,我们仍然可以“调用”该对象,效果是运行由absObj对象定义的重载调用操作符,该操作符接受一个int值并返回它的绝对值。
函数对象经常用作通用算法的实参。(详见P450)
57、函数对象的函数适配器(P453)
标准库提供了一组函数适配器(function adapter),用于特化和扩展一元和二元函数对象。函数适配器分为如下两类:
(1)绑定器(binder),是一种函数适配器,它通过将一个操作数绑定到给定值而将二元函数对象转换为一元函数对象。(bind1st和bind2nd 更多)
(2)求反器(negator),是一种函数适配器,它将谓词函数对象的真值求反。(not1和not2 更多)
58、转换操作符(P455)
转换为什么有用?(详见P454)
转换函数采用如下通用形式:
operator type();
这里,type表示内置类型名、类类型名或由类型别名所定义的名字。对任何可作为函数返回类型的类型(除了void之外)都可以定义转换函数。一般而言,不允许转换为数组或函数类型,转换为指针(数据或函数指针)以及引用类型是可以的。
转换函数必须是成员函数,不能指定返回类型,并且形参表必须为空。
转换函数一般不应该改变被转换的对象。因此,转换操作符通常应定义为const成员。
59、只能应用一个类类型转换
类类型转换之后不能再跟另一个类类型转换。如果需要多个类类型转换,则代码将出错。
假设有Integral=>SmallInt=>int,但是如果有一个函数cal(int),那么对于SmallInt si,可以使用cal(si),但对于Integral intVal;则不能使用cal(intVal)。语言只允许一次类类型转换,所以该调用出错。
60、virtual与其他成员函数(P479)
C++中的函数调用默认不使用动态绑定。要触发动态绑定,必须满足两个条件:第一,只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不进行动态绑定;第二,必须通过基类类型的引用或指针进行函数调用。
基类类型引用和指针的关键点在于静态类型(static type,在编译时可知的引用类型或指针类型)和动态类型(dynamic type,指针或引用所绑定的对象的类型,这是仅在运行时可知的)可能不同。