C++ 重载按位与运算符operator&详解
一、什么是按位与运算符的重载
C++ 中的&是一个二元运算符,默认对整数执行按位与:
cpp
int a = 0b1100; int b = 0b1010; int c = a & b; // 0b1000
和+、-、|一样,&也可以被重载,让用户自定义类型也能用&运算。
cpp
class T { public: T operator&(const T& rhs) const { // 返回一个新的 T } };调用形式:
cpp
T x, y; T z = x & y; // 等价于 x.operator&(y)
二、为什么按位与的重载比取地址"安全"得多
对比一元operator&(取地址),二元operator&的重载要温和很多:
| 对比项 | 一元operator& | 二元operator& |
|---|---|---|
| 破坏语言假设 | 是(地址语义) | 否 |
| 影响标准库 | 严重 | 无 |
| 常见性 | 极少 | 较常见 |
| 推荐度 | 强烈不建议 | 视场景而定 |
二元operator&只是一个普通运算符重载,和operator+完全对等,不会破坏语言机制。
三、典型应用场景
| 场景 | 说明 |
|---|---|
| 位标志 (bit flags) | Permissions、FileMode等组合与查询 |
| 集合运算 | 用位图表示集合,&表示交集 |
| DSL / 表达式模板 | 构建查询表达式,如filter & condition |
| 矩阵/向量按元素与 | 数值计算库中按元素逻辑与 |
| 智能位集类 | 自定义bitset风格的类 |
其中位标志是最经典、最实用的场景。
#include <iostream> #include <string> // 权限标志(用无符号整数表示每一位) enum class Perm : unsigned { None = 0, Read = 1u << 0, // 001 Write = 1u << 1, // 010 Execute = 1u << 2, // 100 }; // 权限集合类 class Permissions { public: // 默认构造:无权限 Permissions() : bits_(0) {} // 从单个权限构造 Permissions(Perm p) : bits_(static_cast<unsigned>(p)) {} // 从原始位构造(显式,避免隐式转换) explicit Permissions(unsigned bits) : bits_(bits) {} // ============ 重载按位与 & ============ // 语义:返回两个权限集合的"交集" Permissions operator&(const Permissions& rhs) const { return Permissions(bits_ & rhs.bits_); } // ============ 重载按位与赋值 &= ============ Permissions& operator&=(const Permissions& rhs) { bits_ &= rhs.bits_; return *this; } // ============ 顺带重载 | 和 |= ============ Permissions operator|(const Permissions& rhs) const { return Permissions(bits_ | rhs.bits_); } Permissions& operator|=(const Permissions& rhs) { bits_ |= rhs.bits_; return *this; } // 转 bool:非空即可判断为 true explicit operator bool() const { return bits_ != 0; } // 判断是否包含某个权限 bool has(Perm p) const { return (bits_ & static_cast<unsigned>(p)) != 0; } unsigned raw() const { return bits_; } private: unsigned bits_; }; // 让 `Permissions & Perm` 也能用(对称性) inline Permissions operator&(Permissions lhs, Perm rhs) { return lhs & Permissions(rhs); } int main() { // 组合:Read | Write Permissions rw = Permissions(Perm::Read) | Permissions(Perm::Write); std::cout << "rw.bits = " << rw.raw() << "\n"; // 3 // 1) 用 & 求交集:rw & Read Permissions onlyRead = rw & Permissions(Perm::Read); std::cout << "onlyRead.raw = " << onlyRead.raw() << "\n"; // 1 // 2) 用 if (p & mask) 做权限检查 if (rw & Permissions(Perm::Read)) { std::cout << "有读权限\n"; } if (!(rw & Permissions(Perm::Execute))) { std::cout << "没有执行权限\n"; } // 3) 用 has() 更直观 std::cout << "has(Write)? " << rw.has(Perm::Write) << "\n"; // 1 std::cout << "has(Execute)? " << rw.has(Perm::Execute) << "\n"; // 0 // 4) 用 &= 原地取交集 Permissions p = Permissions(Perm::Read) | Permissions(Perm::Write); p &= Permissions(Perm::Read); std::cout << "p.raw = " << p.raw() << "\n"; // 1 return 0; }