类的作用域
每个类都会定义它自己的作用域(一个类就是一个作用域)。在类的作用域之外,普通的数据和函数成员只能由对象、引用或者指针使用成员访问运算符来访问。对于类类型成员(typedef)则使用作用域运算符访问。
作用域和定义在类外部的成员
在类外部定义成员函数必须同时提供类名和函数名。一旦遇到了类名,定义的剩余部分(包括参数列表和函数体)就在类的作用域之内了。但需要注意的是返回类型中使用的名字都位于类的作用域之外。
名字查找与类的作用域
类的定义分两步处理:
Ⅰ首先编译成员的声明
Ⅱ直到类全部可见后才编译函数体
即编译器处理完类中的全部声明后才会处理成员函数的定义。所以函数体能使用类中定义的任何名字。
用于类成员声明的名字查找
声明中使用的名字,包括返回类型或者参数列表中使用的名字,都必须在使用前确保可见。
类型名要特殊处理
在类中如果成员使用了外层作用域中代表类型的某个名字,则类不能在之后重新定义该名字。
类型名的定义通常出现在类的开始处,这样就能确保所有使用该类型的成员都出现在类名的定义之后。
建议:不要把数据成员名字作为参数或其他局部变量使用。
如果类的成员变量被隐藏了,可以通过加上类的名字或显式地使用this指针来强制访问成员。
如果类外层的对象被隐藏掉了,但仍然可以用作用域运算符访问它。
构造函数再探
构造函数初始值列表
如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值。
在很多类中,初始化和赋值的区别事关底层效率问题:初始化-直接初始化数据成员,赋值-先初始化再赋值。建议养成使用构造函数初始值的习惯。
成员初始化的顺序
成员的初始化顺序与它们在类定义中的出现顺序一致,构造函数初始值列表中初始值的先后顺序并不影响实际的初始化顺序。
最好令构造函数初始值的顺序与成员声明的顺序保持一致。而且如果可能的话,尽量避免使用某些成员初始化其他成员。
如果一个构造函数为所有参数都提供了默认实参,则它实际上也定义了默认构造函数。
例:
Person::Person(int humanAge = 0): age(humanAge) {}
委托构造函数
委托构造函数和其他构造函数一样,也有一个成员初始值列表和一个函数体。成员初始值列表只有一个唯一的入口,就是类名本身。和其他成员初始值一样,类名后面紧跟圆括号括起来的参数列表,参数列表必须与类中另外一个构造函数匹配。
当一个构造函数委托给另一个构造函数时,受委托的构造函数的初始值列表和函数体被依次执行。
例:
Sales_data(std::string s) : Sales_data(s, 0, 0) {}
默认构造函数的作用
当对象被默认初始化或值初始化时自动执行默认构造函数。
在实际中,如果定义了其他构造函数,那么最好也提供一个默认构造函数。
使用默认构造函数
类名 对象名;
例:
Sales_data obj;
隐式的类类型转换
如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称作转换构造函数。
抑制构造函数的隐式转换
可以通过将构造函数声明为explicit以阻止构造函数用于隐式地创建类对象。
关键字explicit只对一个实参的的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所以无须将这些函数指定为explicit的。
只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复。
用explicit关键字声明构造函数时,它将只能以直接初始化的形式使用。而且,编译器将不会在自动转换过程中使用该构造函数。例:
Sales_data item1(null_book); //正确:直接初始化
为转换显示地使用构造函数
可以使用explicit的构造函数显示地强制进行转换。例:
Sales_data item = static_cast<Sales_data>(cin);
类的静态成员
有时候类需要它的一些成员与类的本身直接相关,而不是与类的各个对象保持关联。
声明静态成员
我们通过在声明之前加上关键字static使得其与类关联在一起。静态成员可以是public或private的。
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。
类的成员函数也不与任何对象绑定在一起,它们不包含this指针。所以,静态成员函数不能被声明成const的,也不能在static函数体里使用this指针。
使用类的静态成员
使用作用域运算符直接访问静态成员。
使用类的对象,引用或指针来访问静态成员。
成员函数能直接使用静态成员。
定义静态成员
static关键字只出现在类内部的声明语句。
只有静态常量成员能在类的内部初始化,同时也应该在类的外部定义一下该成员。
必须在类外部定义(只能定义一次)和初始化每个静态成员。例:
double Account::interestRate = initRate(); //定义并初始化一个静态变量
C++基础部终于复习完了,接下来开始细看标准库,同时也开始复习数据结构,看看算法,冲鸭!