2009-02-07 6 views
1

J'essaie d'écrire une petite classe pour mieux comprendre les drapeaux de bits en C++. Mais quelque chose ne marche pas. Il imprime les mauvaises valeurs. Où est le problème? Ai-je mal compris comment ajouter des drapeaux? Ou vérifier si le champ de bits les a?Enum bitfield container class

Heres le code:

#include <iostream> 

enum flag 
{ 
    A = 1, B = 2, C = 4 
}; 

class Holder 
{ 
public: 
    Holder() : m_flags(A) {} 
    ~Holder() {} 

    void add_flag(flag f) { m_flags |= f; } 
    bool has_flag(flag f) { return ((m_flags&f)==f); } 
    void remove_flag(flag f) 
    { 
     unsigned int flags = 0; 
     for (int i = 1; i<=(int)C; i *= 2) 
     { 
      if ((flag)i!=f && has_flag(f)) 
       flags |= f; 
     } 
     m_flags = flags; 
    } 

    void print() 
    { 
     std::cout << "flags are now: " << m_flags << " | holding: "; 
     for (int i = 1; i<=(int)C; i *= 2) 
     { 
      if (has_flag((flag)i)) 
       std::cout << i << " "; 
     } 
     std::cout << std::endl; 
    } 

private: 
    unsigned int m_flags; 
}; 

int main() 
{ 
    Holder h; 
    h.print(); // should print 1 

    h.add_flag(B); 
    h.print(); // should print 1 2 

    h.remove_flag(A); 
    h.print(); // should print 2 

    h.add_flag(C); 
    h.print(); // should print 2 4 

    h.remove_flag(B); 
    h.print(); // should print 4 
} 

sortie du programme:

flags are now: 1 | holding: 1 
flags are now: 3 | holding: 1 2 
flags are now: 1 | holding: 1 
flags are now: 5 | holding: 1 4 
flags are now: 0 | holding: 

Répondre

3

Personnellement, j'utiliser std :: vector < bool> pour gérer les drapeaux, car il est une spécialisation qui emballe bools dans peu.

Cependant:

Je pense que votre drapeau supprimer est un peu complexe, essayez cette place

void remove_flag(flag f) 
{ 
    if (has_flag(f) == true) 
    { 
     m_flags ^= f; // toggle the bit leaving all other unchanged 
    } 
} 

Edit: Un commentaire m'a demandé pourquoi je n'ai pas do m_flags &= ~f. J'ai pris la question comme une question «apprenant» pas une question d'optimisation. Je montre comment rendre son code correct, pas rapide.

+1

Effacement d'un drapeau est probablement plus rapide (et plus simple) si cela est fait sans vérification préalable. –

+0

vous avez raison. J'ai supposé que c'était une expérience d'apprentissage pour le PO et j'ai simplement corrigé son code pour travailler. Je n'ai pas corrigé son code pour le rendre plus rapide. –

+0

Que se passe-t-il si f a plus de 1 bit défini, mais que tous ne sont pas définis dans flag? flag & = ~ f résout cela. –

3

Il y a un bug dans votre méthode remove_flag(), il devrait être drapeaux | = i;

Mais, faites-O (1) comme ceci:

void remove_flag(flag f) { m_flags &= ~f; } 
3

has_flag() et remove_flag() ont tort. Ils devraient aller comme ceci:

bool has_flag(flag f) { return !!(m_flags & f); } 
void remove_flag(flag f) 
{ 
    m_flags &= ~f; 
} 
+0

Son implémentation has_flag fonctionne très bien. – Eclipse

+0

Eh bien, il ne devrait pas. –

0

Tout le monde a déjà cloué ceci: flag & = ~ f;

You might look at my earlier posting.

has_flag(): Vous cherchez à retourner vrai si tous les bits f sont fixés? Ou si au moins l'un d'entre eux est défini? C'est la différence entre les drapeaux & f == f   vs   drapeaux & f  ! = 0.

Vous pourriez envisager #include <iomanip> et Cout < < hex < < m_flag < < décembre (La conversion hexadécimale peut être plus facilement effectuée dans votre tête.)

L'énumération peut être à l'intérieur du support de classe.

class Holder 
{ 
public: 
    enum flag { A=1, B=2, C=4; }; 
... 
}; 

Vous pouvez ensuite utiliser Holder :: A au lieu de A.

Vous pouvez utiliser pour (i = 0; i < N; i ++) si has_flag (1 < < i) ...

Vous pouvez vos méthodes add_flag/has_flag/de remove_flag de prendre un int plutôt que le type énuméré. Cela se débarrasse de beaucoup de casting.Si vous ne voulez pas prendre en charge toutes les valeurs int possibles, une méthode de validation et un chemin de rejet peuvent être utilisés. Au fait, rien ne m'empêche d'appeler add_flag (flag (5736)). Et vous lancez fréquemment enum_flag.

Vous pouvez utiliser mFlag plutôt que m_flag. C'est ton choix. Mais quand vous regardez le code comme m_x * m_y-m_z * m_y-m_x * m_z, en fonction de votre police, il peut être facile de confondre _ pour -. (Ou vice versa.)

De même, considérons addFlag plutôt que add_flag. Pour quelque chose comme ça, peu importe. Mais lorsque vous avez un long nom descriptif, ces traits de soulignement commencent à s'additionner, en utilisant l'espace de ligne. La tentation est alors d'abréger le nom, rendant votre code plus obtus.

Juste mes 0,02 $.