赞
踩
之前学习过全局(文件)作用域和局部(代码块)作用域。全局作用域的变量可以在其所属文件的任何地方使用它,而局部作用域的变量只能在其所属的代码块中使用。函数名的作用域不能是局部作用域 —— 不能在函数中定义函数。C++ 引入了一个新的作用域 —— 类作用域。
类作用域:在类中定义的名称的作用域为整个类。例如,类的数据成员名和成员函数名。作用域为整个类的名称只在该类中是已知的,在类外是不可知的。因此,可以在不同类中使用相同的类成员名而不会引起冲突。另外,类作用域意味着不能从外部直接访问类的成员,公有函数也是如此。也就是说,如果要调用公有成员函数,必须通过对象调用。同样,在定义成员函数时,必须使用作用域解析运算符。
总之,在类声明或成员函数定义中,可以使用未修饰的成员名称(非限定名),即直接使用成员函数的函数名。构造函数名称在被调用时,才能被识别,因为它的名称与类名相同。在其他情况下(类外),使用类成员名时,必须根据上下文使用运算符,例如,对象使用直接成员运算符(.),指针使用间接成员运算符(->),函数定义使用作用域解析运算符(::)。
有时候,在类声明中定义一个常量很有用。例如,在类声明中可能会使用字面值 30 来指定数组的长度。你可能会认为应该这样声明:
class Demo {
private:
const int LENGTH = 30;
int arr[LENGTH];
...
}
事实上,这样是不行的。类声明只是描述类对象的形式,并没有真正创建类对象。因此,在创建类对象之前,并没有用于存储值的空间,所以创建 arr 的时候会报错。
想要在类中定义一个常量有两种方法:枚举、static 关键字。这两种方案都可以实现在类内定义一个常量,并且效果相同。
在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。也就是说,可以这样定义类的声明:
注意,用这种方式声明的枚举并不会创建类数据成员。也就是说,所有对象中都不包含枚举。另外, LENGTH 只是一个符号名称,在作用域为整个类的代码中遇到它时,编译器将用 30 代替它。
由于这里使用枚举只是为了创建符号常量,并不需要创建枚举类型的变量,所以不需要提供枚举名。顺便说一句,在很多实现中,ios_base 类在其公共部分中完成了类似的工作:
// ios_base.h
class ios_base {
public:
...
enum { _S_local_word_size = 8 };
...
}
C++ 提供了另一种在类中定义常量的方式 —— 使用关键字 static:
这将创建一个名为 LENGTH 的常量,该常量将会和其他静态变量存储在一起,而不是存储在对象中。因此,只有一个 LENGTH 常量,它被所有的对象共享。这里只是简单了解下 static 常量,关于静态类成员相关知识以后会详细学习。
C++ 98 中,static 只能声明整型或枚举的静态常量,不能存储 double,而 C++ 11 消除了这种限制。
传统的枚举存在一些问题,例如,两个枚举定义中的枚举量可能存在冲突;存在类型安全问题(类型转换)等。
因为 enum1 和 enum2 位于相同的作用域内,它们将发生冲突。为了避免这种情况,C++ 11 提供了一种新枚举,其枚举量的作用域为类作用域。
也可以用 struct 来代替 class,但不论是那种形式,使用枚举量的时候都需要使用枚举量的限定名。
int a = (int) enum1::Small;
enum1 s = enum1::Small;
enum1 t = (enum1) 3;
枚举量的作用域为类之后,在不同的枚举定义中的枚举量就不会发生名称冲突了。另外,C++ 11 还提高了作用域内枚举的类型安全 —— 作用域内枚举不能隐式转换为整型。在必要时,可以使用显式类型转换。这意味着上述代码中将强制类型转换去除之后会报错。
枚举在底层是用某种整型类型表示。在 C++ 98 中,如何选择是取决于实现,因此枚举的长度可能随系统而异。但 C++ 11 消除了作用域内枚举的这种依赖性。默认情况下,C++ 11 作用域内枚举的底层类型为 int。另外,还提供了一种语法,用于做出不同的选择:
enum class enum3:short{
Small, Medium
};
:short 将底层类型指定为 short。底层类型必须为整型。
PS: 《C++ Primer Plus》中是 enum class : short pizza { Small, Medium },但我这样写会报错。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。