我试图编写一个小类来更好地理解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:
答案 0 :(得分:3)
你的remove_flag()方法有一个错误,它应该是flags | = i;
但是,这样做O(1):
void remove_flag(flag f) { m_flags &= ~f; }
答案 1 :(得分:3)
has_flag()和 remove_flag()错误。它们应该是这样的:
bool has_flag(flag f) { return !!(m_flags & f); }
void remove_flag(flag f)
{
m_flags &= ~f;
}
答案 2 :(得分:3)
我个人会使用std :: vector&lt; bool&gt;处理标志,因为它是一个将bool打包成bit的专业化。
然而:
我认为你的删除标志有点复杂,试试这个
void remove_flag( flag f )
{
if ( has_flag( f ) == true )
{
m_flags ^= f; // toggle the bit leaving all other unchanged
}
}
编辑:
评论问为什么我没有do m_flags &= ~f
。我将问题视为“学习者”问题而不是优化问题。我展示了如何使他的代码正确,而不是快速。
答案 3 :(得分:0)
每个人都已经钉了这个:flag&amp; =〜f;
You might look at my earlier posting.
has_flag():如果设置了f中的所有位,是否要返回true?或者,如果至少设置了其中一个?这是flag&amp; f == f vs flags&amp; f!= 0。
之间的区别您可以考虑#include&lt; iomanip&gt;和cout&lt;&lt;十六进制&lt;&lt; m_flag&lt;&lt; dec。 (可以更容易地在头脑中完成十六进制到位转换。)
枚举可以在班主持人内部。
class Holder
{
public:
enum flag { A=1, B=2, C=4; };
...
};
然后您将使用 Holder :: A 而不是 A 。
如果has_flag(1&lt;&lt;&lt; i)...
,您可能想要使用for(i = 0; i&lt; N; 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美元。