在类中定义的名称(如类数据成员和类成员函数名)的作用域都为整个类,作用域为整个类的名称只有在该类中是已知的,在类外是不可知的。因此,可以在不同类中使用相同的类成员名而不会引起冲突。
Stock sleeper("Exclusive Ore", 100, 0.25); // create object
sleeper.show(); // use object to invoke a member function
show(); // invalid -- can’t call method directly
总之,在类声明或成员函数定义中,可以使用未修饰的成员名称(未限定的名称),就像ViewIk()调用disp()成员函数时那样。
class Ik
{
private:
int fuss; // fuss has class scope
public:
Ik(int f = 9) { fuss = f; } // fuss is in scope
void ViewIk() const; // ViewIk has class scope
void disp() const;
};
void Ik::ViewIk() const //Ik:: places ViewIk into Ik scope
{
cout << fuss << endl; // fuss in scope within class methods
disp();//不需要限定修饰符
}
...
int main()
{
Ik* pik = new Ik;
Ik ee = Ik(8); // constructor in scope because has class name
ee.ViewIk(); // class object brings ViewIk into scope
pik->ViewIk(); // pointer-to-Ik brings ViewIk into scope
...
return 0;
}
有时候,类作用域常量很有用。例如,类声明可能使用字面值30来指定数组的长度,由于该常量对于所有对象来说是相同的,因此创建一个由所有对象共享的常量是个不错的主意。
第一种方法实现类作用域常量:
声明一个枚举。在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。
class Bakery
{
private:
enum {Months = 12};
double costs[Months];
...
}
注意,用这种方式声明枚举并不会创建类数据成员。也就是说,所有对象中都不包含枚举。另外,Months只是一个符号名称,在作用域为整个类的代码中遇到它时,编译器将用12替换它。
这里使用枚举只是为了创建符号常量,并不打算创建枚举类型的变量,因此不需要提供枚举名。在很多实现中,ios_base在其共有部分完成了类似的工作,诸如ios_base::fixed等标识符就来自这里。其中fixed是ios_base类中定义的典型的枚举量。
第二种方法实现类作用域常量:使用static关键字
如下所示,创建了一个名为Months的常量,该常量将与其他静态变量存储在一起,而不是存储在对象中。因此,只有一个Months常量,被所有Bakery对象共享。
class Bakery
{
private:
static const int Months = 12;
double costs[Months];
...
}
传统的枚举存在一些问题,其中之一是两个枚举定义中的枚举量可能发生冲突。
enum egg {Small, Medium, Large, Jumbo};
enum t_shirt {Small, Medium, Large, Xlarge};
这将无法通过编译,因为egg的Small和t_shirt的Small位于同一个作用域内,他们将发生冲突。
C++提供了一种新枚举,其枚举量的作用域为类。
enum class egg {Small, Medium, Large, Jumbo};
enum class t_shirt {Small, Medium, Large, Xlarge};
也可以使用struct代替class,无论使用哪种方式,都需要使用枚举名来限定枚举量:
egg choice = egg::Large; // the Large enumerator of the egg enum
t_shirt Floyd = t_shirt::Large; // the Large enumerator of the t_shirt enum
枚举量的作用域为类,不同枚举定义中的枚举量就不会发生名称冲突了。
C++11还提高了作用域内枚举的类型安全。在有些情况下,常规枚举将自动转换为整型,如将其赋值给int变量或用于比较表达式时,其作用域内枚举不能隐式的转换为整型。
enum egg_old {Small, Medium, Large, Jumbo}; // unscoped
enum class t_shirt {Small, Medium, Large, Xlarge}; // scoped
egg_old one = Medium; // unscoped
t_shirt rolf = t_shirt::Large; // scoped
int king = one; // implicit type conversion for unscoped
int ring = rolf; // not allowed, no implicit type conversion
if (king < Jumbo) // allowed
std::cout << "Jumbo converted to int before comparison.\n";
if (king < t_shirt::Medium) // not allowed
std::cout << "Not allowed: < not defined for scoped enum.\n";
但是可以使用强制类型转换:
int Frodo = int(t_shirt::Small); // Frodo set to 0
枚举用某种底层整型类型表示,在C++98中,如何选择取决于实现,因此包含枚举的结构的长度随系统而异。对于作用域内枚举,C++11消除了这种依赖性。默认情况下,C++11作用域内枚举的底层类型为int。另外,还提供了一种语法,可用于做出不同的选择:
// underlying type for pizza is short
enum class : short pizza {Small, Medium, Large, XLarge};
short将底层类型指定为short。