【问题标题】:C++ checking enum flagsC++ 检查枚举标志
【发布时间】:2011-09-09 19:20:42
【问题描述】:

在我的一个类中,我有一个整数,它存储一组枚举标志,如下所示:

enum AttackFlags
{
    Contact = 1,                        //Move connects with target
    Projectile = 2,                         //Attack is projectile based
    Unblockable = 4,                        //Attack can not be blocked
    UncounterableLv1 = 8,                   //Attack can't be countered except by extreme counter attack skills/status effects
    UncounterableLv2 = 16,                  //Attack can not be countered
    Flinches = 32,                          //Has a chance to stun the enemy, pushing back their next turn
    Unreflectable = 64,                     //Attack penetrates reflect. Only checked for Magic attacks
    IgnoreDefenderStatusEffects = 128,      //Ignores active status effects on the defender
    IgnoreAttackerStatusEffects = 256,      //Ignores active status effects on the attacker
    IgnoreDefenderAbilities = 512,          //Ignore the defenders abilities
    IgnoreAttackerAbilities = 1024,         //Ignore the attackers abilities
    IgnoreArmorRating = 2048,               //Ignore the defensive boosts of armor
    IgnoreWeaponRating = 4096,              //Ignore the attack boost from weapons
    HighCritical = 8192,                    //The move has an increased chance to crit
    CausesStatus = 16384,                   //Can the move cause status effects?
    Elemental = 32768,                      //Is the move elemental based?
    Unimplemented = 65536,                  //has the move been implemented yet?
    ModsTimer = 131072,                     //Does it have an effect on the target or users timer?
    Heals = 262144,                         //Does the move heal?
    SecondaryEffects = 524288,              //Attack has additional effects besides basic attack
    PhysicalAttackFlag = 1048576,           //Is the Class Physically based? I.E. blocked by Protect and Shield
    MagicAttackFlag = 2097152,              //Is the move Magically Based? I.E. is it affected by things like Shell
    MultiHit = 4194304,                     //Does it enxcapsulate more then 1 hit
    SingleUse = 8388608,                    //Attack can only be used once per battle
    DoesNotCauseDamage = 16777216
};

class Attack
{
   int AtkFlags; //Stores AttackFlags |'d together

}

我想向我的 Attack 类添加一个具有以下签名的方法

bool HasAttackFlags(int flags);

flags 将有许多 AttackFlags |'d 一起。如果我只想检查一个标志,我可以将 & AtkFlags 和标志放在一起,但是因为我必须检查多个可能的标志,所以这不起作用。如何正确检查多个标志?我想避免传递一个向量/一组标志来检查,因为简单地|将一组标志放在一起比构造一个向量/组更简单

提前致谢

编辑:

为了澄清我的意思,我可能有以下内容

Attack atk;
atk.AtkFlags = Contact | Projectile | Heals | MagicAttackFlag;

然后,我想像这样检查 atk 上的标志:

bool res = atk.HasAttackFlags(Contact | Projectile);

res 应该为真,反之亦然

bool res = atk.HasAttackFlags(Contact | Unreflectable);

应该是假的,因为 AtkFlags 不包含 Contact 和 Unreflectable。

【问题讨论】:

    标签: c++ enums


    【解决方案1】:

    我不确定我是否在关注您的问题,因为您似乎提到了明显的解决方案。那么作为解决方案有什么问题,显然添加您希望的任何其他标志:

    bool HasAttackFlags(int flags) {
        return (flags&(contact|projectile))!=0;
    }
    

    编辑:哦...我想我刚刚想通了,你想检查是否存在 2 个或更多标志作为一组?在这种情况下,您可以简单地将方法修改为:

    bool HasAttackFlags(int flags) {
        return (flags&(contact|projectile))==(contact|projectile);
    }
    

    【讨论】:

    • 如果启用了任何标志,则第一个示例代码返回 true,如果启用了所有标志,则第二个示例代码返回 true。只是为了澄清。
    【解决方案2】:

    这是我的建议:

    注意使用枚举定义来启用机器

    enum AttackFlags
    {
        Contact                     = 1ul <<  0,  // Move connects with target
        Projectile                  = 1ul <<  1,  // Attack is projectile based
        Unblockable                 = 1ul <<  2,  // Attack can not be blocked
        UncounterableLv1            = 1ul <<  3,  // Attack can't be countered except by extreme counter attack skills/status effects
        UncounterableLv2            = 1ul <<  4,  // Attack can not be countered
        Flinches                    = 1ul <<  5,  // Has a chance to stun the enemy, pushing back their next turn
        Unreflectable               = 1ul <<  6,  // Attack penetrates reflect. Only checked for Magic attacks
        IgnoreDefenderStatusEffects = 1ul <<  7,  // Ignores active status effects on the defender
        IgnoreAttackerStatusEffects = 1ul <<  8,  // Ignores active status effects on the attacker
        IgnoreDefenderAbilities     = 1ul <<  9,  // Ignore the defenders abilities
        IgnoreAttackerAbilities     = 1ul << 10,  // Ignore the attackers abilities
        IgnoreArmorRating           = 1ul << 11,  // Ignore the defensive boosts of armor
        IgnoreWeaponRating          = 1ul << 12,  // Ignore the attack boost from weapons
        HighCritical                = 1ul << 13,  // The move has an increased chance to crit
        CausesStatus                = 1ul << 14,  // Can the move cause status effects?
        Elemental                   = 1ul << 15,  // Is the move elemental based?
        Unimplemented               = 1ul << 16,  // has the move been implemented yet?
        ModsTimer                   = 1ul << 17,  // Does it have an effect on the target or users timer?
        Heals                       = 1ul << 18,  // Does the move heal?
        SecondaryEffects            = 1ul << 19,  // Attack has additional effects besides basic attack
        PhysicalAttackFlag          = 1ul << 20,  // Is the Class Physically based? I.E. blocked by Protect and Shield
        MagicAttackFlag             = 1ul << 21,  // Is the move Magically Based? I.E. is it affected by things like Shell
        MultiHit                    = 1ul << 22,  // Does it enxcapsulate more then 1 hit
        SingleUse                   = 1ul << 23,  // Attack can only be used once per battle
        DoesNotCauseDamage          = 1ul << 24, 
    
        MaskAttack      = MagicAttackFlag | PhysicalAttackFlag,
        MaskIgnore      = IgnoreWeaponRating | IgnoreArmorRating | IgnoreAttackerAbilities | IgnoreDefenderAbilities | IgnoreAttackerStatusEffects,
        // etc
    };
    
    static bool HasAttackFlag(AttackFlags flags)
    {
        return flags & MaskAttack;
    }
    
    static bool HasIgnoreFlag(AttackFlags flags)
    {
        return flags & MaskIgnore;
    }
    

    作为额外的奖励,考虑一种仅返回“杂项”(可以说是未屏蔽)标志的方法:

    static AttackFlags MiscFlags(AttackFlags flags)
    {
        return (AttackFlags) (flags & ~(MaskAttack | MaskIgnore));
    }
    

    【讨论】:

    • 我从来没有见过这种初始化枚举的方式,我总是看到= 1&lt;&lt; 0=1&lt;&lt; 1=1&lt;&lt; 2等,所以如果你犯了错误很明显。
    • @Mooing:不同的目标。我想我同样喜欢这种方法。好吧,在这么大的枚举中可能会更好。我会接受这个建议!
    【解决方案3】:

    例如,您可以这样做:

    int v = Unblockable | UncounterableLv1| UncounterableLv;
    if ((flags & v ) == v)
    {
      //flags has all three: Unblockable, UncounterableLv1 and UncounterableLv
    }
    else if ( (flags & v ) ==  (Unblockable | UncounterableLv1))
    {
      //flags has Unblockable and UncounterableLv1
    }
    else if ( (flags & v ) ==  Unblockable )
    {
      //flags has Unblockable only
    }
    //and so on
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-14
      相关资源
      最近更新 更多