1

我试图编写一个小类来更好地理解 C++ 中的位标志。但有些事情没有解决。它打印错误的值。哪里有问题?我是否误解了如何添加标志?或者检查位域是否有它们?

继承人的代码:

#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
}

程序输出:

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: 
4

4 回答 4

3

您的 remove_flag() 方法中有一个错误,它应该是 flags |= i;

但是,这样做 O(1) 像这样:

void remove_flag(flag f) { m_flags &= ~f; }
于 2009-02-07T16:17:45.313 回答
3

has_flag()remove_flag()是错误的。他们应该是这样的:

bool has_flag(flag f) { return !!(m_flags & f); }
void remove_flag(flag f) 
{
    m_flags &= ~f;
}
于 2009-02-07T16:20:05.790 回答
3

我个人会使用 std::vector< bool > 来处理标志,因为它是一种将布尔值打包成位的专业化。

然而:

我认为你的删除标志有点复杂,试试这个

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

编辑:评论问我为什么不这样做do m_flags &= ~f。我把这个问题当作“学习者”问题而不是优化问题。我展示了如何使他的代码正确,而不是快速。

于 2009-02-07T16:24:04.253 回答
0

每个人都已经确定了这一点:flag &= ~f;

你可以看看我之前的帖子。

has_flag():如果 f 中的所有位都已设置,您是否希望返回 true?或者如果至少设置了其中一个?这是 flags&f==f 与 flags&f !=0 之间的区别。

您可以考虑 #include <iomanip> 和 cout << hex <<m_flag <<dec. (十六进制到位的转换可以在您的脑海中更轻松地完成。)

枚举可以在类 Holder 中。

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

然后,您将使用Holder::A而不是A

如果 has_flag(1<<i) ...

您可能希望 add_flag/has_flag/remove_flag 方法采用 int 而不是枚举类型。这摆脱了很多铸造。如果您不想支持所有可能的 int 值,可以使用验证方法和拒绝路径。顺便说一句,没有什么能阻止我调用 add_flag(flag(5736))。而且您已经非常频繁地投射到 enum_flag 。

您可能想要使用 mFlag 而不是 m_flag。这是你的选择。但是当您查看 m_x*m_y-m_z*m_y-m_x*m_z 之类的代码时,根据您的字体,很容易将 _ 误认为 -。(或相反亦然。)

同样,考虑 addFlag 而不是 add_flag。对于这样的事情,这并不重要。但是当你有一个长的描述性名称时,这些下划线开始加起来,占用了行空间。然后诱惑是缩写名称,使您的代码更加迟钝。

只是我的 0.02 美元。

于 2009-02-07T16:53:41.543 回答