枚举


有时候,你会想要定义一组相关的常数,例如,以一组常数来代表游戏中动作:

#include <iostream> 
using namespace std; 

struct Action {
    const static int STOP = 0;
    const static int RIGHT = 1;
    const static int LEFT = 2;
    const static int UP = 3;
    const static int DOWN = 4;
};

void play(int action) {
    switch(action) {
        case Action::STOP:
            cout << "播放停止动画" << endl;
            break;
        case Action::RIGHT:
            cout << "播放向右动画" << endl;
            break;
        case Action::LEFT:
            cout << "播放向左动画" << endl;
            break;
        case Action::UP:
            cout << "播放向上动画" << endl;
            break;
        case Action::DOWN:
            cout << "播放向下动画" << endl;
            break;
        default:
            cout << "不支持此动作" << endl;
    }
} 

int main() { 
    play(Action::RIGHT);
    play(Action::LEFT);

    return 0;
}

这种方式虽然行得通,不过play接受的是int整数,这表示你可以传入任何int整数,而不一定要是枚举的数值,虽然可以透过设计,令枚举的static成员为Action的实例,并令其成为单例(singleton)等,不过,C++ 本身就提供了enum来达到这类任务。例如:

#include <iostream> 
using namespace std; 

enum Action {
    STOP, RIGHT, LEFT, UP, DOWN
};

void play(Action action) {
    switch(action) {
        case Action::STOP:
            cout << "播放停止动画" << endl;
            break;
        case Action::RIGHT:
            cout << "播放向右动画" << endl;
            break;
        case Action::LEFT:
            cout << "播放向左动画" << endl;
            break;
        case Action::UP:
            cout << "播放向上动画" << endl;
            break;
        case Action::DOWN:
            cout << "播放向下动画" << endl;
            break;
        default:
            cout << "不支持此动作" << endl;
    }
} 

int main() { 
    play(Action::RIGHT);
    play(LEFT);
    play(1); // error: invalid conversion from 'int' to 'Action'

    return 0;
}

enum枚举的成员具有类型,以上例来说,STOP等成员都是Action类型,因此play接受是Action的成员,就上例来说,Action等成员,可见范围会与使用enum处的范围相同,因此上例可以直接使用LEFT而不一定使用Action::前置,然而,如果有其他enum枚举了同名的成员,省略Action::就会发生名称冲突。

enum枚举的成员,会有默认的对应整数,无范畴的枚举成员,在必须获取整数值的场合,会自动转换为对应的整数,对应整数默认由 0 开始,也可以自行指定。例如:

enum Action {
    STOP = 1, RIGHT, LEFT, UP, DOWN
};

就上例来说,Action::STOP对应的整数为后续枚举成员没有设定对应数值的话,会自动递增 1,所以Action::RIGHT为 2、Action::LEFT为 3,依此类推,然而枚举成员对应的常数值不需独一无二,例如:

enum Action {
    STOP = 1, RIGHT, LEFT = 1, UP, DOWN
};

对于无范畴的enum成员,C++ 标准只保证对应的整数类型,可以容纳被指定的整数值,若无法容纳则编译错误,不过在 C++ 11 以后可以指定类型:

enum Action : int {
    STOP, RIGHT, LEFT, UP, DOWN
};

C++ 11 以后也可以先定义而不定义枚举成员:

enum Action : int;

C++ 11 可以定义有范畴的枚举成员,也就是可视范围是在enum之内,使用时就必须加上类型前置:

#include <iostream> 
using namespace std; 

enum class Action {
    STOP, RIGHT, LEFT, UP, DOWN
};

void play(Action action) {
    switch(action) {
        case Action::STOP:
            cout << "播放停止动画" << endl;
            break;
        case Action::RIGHT:
            cout << "播放向右动画" << endl;
            break;
        case Action::LEFT:
            cout << "播放向左动画" << endl;
            break;
        case Action::UP:
            cout << "播放向上动画" << endl;
            break;
        case Action::DOWN:
            cout << "播放向下动画" << endl;
            break;
        default:
            cout << "不支持此动作" << endl;
    }
} 

int main() { 
    play(Action::RIGHT);
    play(LEFT); // error: 'LEFT' was not declared in this scope

    return 0;
}

定义有范畴的枚举时,可以使用classstruct,两者等效,有范畴的枚举不会自动转换为对应的整数值,必要时得明确指定转型:

int action = static_cast<int>(Action::RIGHT);




展开阅读全文