C++类的常量数据成员,静态数据成员,常量静态数据成员
const成员
const成员可以提供类内初始值,也可以在构造函数初始化列表中进行初始化。
#include <iostream>
using namespace std;
class A {
public:
A(int temp) :j(temp){}
A(int a, int b) : i(a), j(b) {}
void print()
{
cout << "i: " << i << " " << "j: " << j << endl;
}
private:
const int i = 3;
const int j;
};
int main()
{
A a(4);
a.print();
A a1(5, 6);
a1.print();
return 0;
}
/*
i: 3 j: 4
i: 5 j: 6
*/
const成员为什么不能在构造函数体中进行赋值呢?
构造函数创建对象时,对象在执行构造函数体执行前被创建(即分配存储空间)。因此,调用构造函数将为对象的成员变量分配内存,然后程序进入构造函数体内,使用常规的赋值方式对成员变量进行赋值。因此,对于const
数据成员,必须在执行到构造函数体之前,即创建对象,进行初始化。
static成员
初始化在类外,且不能加static修饰,且不能在类内提供初始值
#include <iostream>
using namespace std;
class A {
public:
static int i;
void print()
{
cout << i << endl;
}
};
int A::i = 10;
int main()
{
A a;
a.print(); //输出10
return 0;
}
静态整型常量数据成员
#include <iostream>
using namespace std;
class A{
public:
void print1()
{
cout << "i: " << i << " " << "j: " << j << endl;
}
private:
static const int i = 30;
static const int j;
}
const int A::j = 20; //静态常量数据成员,在类外定义时,要加上const关键字
//const int A::i = 5; //error,因为已经在类内定义过了,这样的话就是重复定义
int main()
{
A a;
a.print1();
return 0;
}
- 只有静态整型常量才可以在类内提供初始值。如果是
static const double/float
则不可以在类内提供初始值。static const int/short
可以在类内提供初始值。 - 如果静态整型常量在类内没有提供初始值,在类外初始化时,要加上
const
关键字。 - 如果静态整型常量已经在类内提供初始值了,在类外不可以再次初始化,因为这样就重复定义了,可以只在类外声明。
C++枚举类型
枚举类型定义格式为
enum <类型名> {<枚举常量表>};
应用举例
enum color_set1 {RED, BLUE, WHITE, BLACK}; //定义枚举类型color_set1
enum week {Sun, Mon, Tue, Wed, Thu, Fri, Sat}; //定义枚举类型week
枚举变量代表该枚举类型的变量可能取的值,编译系统为每个枚举常量指定一个整数值,默认状态下,这个整数就是所列举元素的序号,序号从0开始,可以在定义枚举类型时为部分或全部枚举常量指定整数值,在指定值之前的枚举常量仍按默认方式取值,而指定值之后的枚举常量按依次加1的原则取值,各枚举常量的值可以重复。
enum fruit_set {apple, orange, banana=1, peach, grape}
//枚举常量apple=0,orange=1, banana=1,peach=2,grape=3
enum week {Sun=7, Mon=1, Tue, Wed, Thu, Fri, Sat};
//枚举常量Sun,Mon,Tue,Wed,Thu,Fri,Sat的值分别为7、1、2、3、4、5、6
枚举常量只能以标识符形式表示,而不能是整形,字符型等文字常量,以下定义非法:
enum letter_set {'a','d','F','s','T'}; //枚举常量不能是字符常量
enum year_set{2000,2001,2002,2003,2004,2005}; //枚举常量不能是整型常量
枚举变量的值只能取枚举常量表中所列的值,就是整型数的一个子集。
枚举变量占用内存的大小与整型数相同。
枚举变量只能参与赋值和关系运算以及输出操作,参与运算时用其本身的整数值。
enum color_set1 {RED, BLUE, WHITE, BLACK} color1, color2;
enum color_set2 { GREEN, RED, YELLOW, WHITE} color3, color4;
则允许的赋值操作如下:
color3=RED; //将枚举常量值赋给枚举变量
color4=color3; //相同类型的枚举变量赋值,color4的值为RED
int i=color3; //将枚举变量赋给整型变量,i的值为1
int j=GREEN; //将枚举常量赋给整型变量,j的值为0
允许的关系运算符有 = = , < , > , < = , > = , ! = ==,<,>,<=,>=, != ==,<,>,<=,>=,!=,例如:
//比较同类型枚举变量color3,color4是否相等
if (color3==color4) cout<<"相等";
//输出的是变量color3与WHITE的比较结果,结果为1
cout<< color3<WHITE;
枚举变量可以直接输出,输出的是变量的整数值。
cout << color3; //输出的是color3的整数值,即RED的整数值1
重要提示
- 枚举变量可以直接输出,但不能直接输入;
- 不能直接将常量赋给枚举变量;
- 不同类型的枚举变量之间不能相互赋值;
C++中作用域受限的枚举类型
一个典型的枚举类型定义如下:
enum Color {RED, BLUE};
这种枚举类型有如下的问题:
-
作用域不受限,枚举变量的作用域不受限,会暴露给邻近的代码作用域(如果在最外层则为全局作用域),容易引起命名冲突,例如如下代码是无法编译通过的。
-
enum Color {RED, BLUE}; enum Feeling {EXCITED, BLUE};
-
-
会隐式转换为
int
,这是C中默认行为,但是和“有类型的常量”的初衷是不符合的,在上面的例子中EXCITED == RED
会返回真。
经典做法
-
使用命名空间
-
namespace Color {enum Type {RED, YELLOW, BLUE}; };
-
这样就可以使用
Color::type c = Color::RED
定义新的枚举变量,如果使用using namespace Color
后,前缀还可以省去,使得代码简化。
-
-
使用一个类或结构体来限定其作用域,例如:
-
struct Color {enum Type {RED, YELLOW, BLUE}; };
-
C++11的枚举类
枚举类使用如下语法定义:
enum class Color { RED, BLACK };
定义新变量也得到了简化:
Color c = Color::RED;
类限制了其作用域,避免了命名冲突,同时也避免了隐式类型转换,也就是说,枚举类即是作用域受限的,又是强类型的枚举,C++11允许枚举类指定存储类型;
enum class Color:char {RED, BLUE};