C++运算符重载:为何10!=i会调用==而非!=运算符?
核心原因
你重载的==和!=都是类的成员函数,这类成员运算符重载有个硬性规则:表达式的左操作数必须是当前Integer类的实例——因为成员函数必须绑定到类对象上,通过隐式的this指针调用,左操作数就是this指向的那个对象。
逐个看三个表达式的匹配逻辑就很清楚:
i != i:左操作数是Integer类实例i,直接匹配成员operator!=,正常输出!=i != 100:左操作数还是Integer实例i,右操作数的字面量100会通过你写的带默认参数的构造函数Integer(int t = 0),隐式转换成临时Integer对象,同样匹配成员operator!=,输出!=10 != i:左操作数是int类型的字面量10,不是Integer类实例,根本无法调用你写的成员operator!=——你不可能给内置类型int追加成员函数。
这时候C20引入的比较运算符重载兜底规则会生效:如果找不到直接匹配的a != b重载,编译器会自动把表达式重写为!(a == b),再查找可用的==重载。如果是C17及更早的标准,这段代码会直接编译报错,因为根本找不到匹配的operator!=重载。
这里重写后的表达式是!(10 == i),查找10 == i的匹配时,左操作数10可以隐式转换为临时Integer对象,临时对象作为左值刚好可以调用成员operator==,传入右操作数i完成匹配,所以最终你看到输出的是==,之后编译器会自动对返回值取反得到!=的逻辑结果。
修复方式
如果想让所有顺序的比较都符合预期,有两种简单方案:
- 把比较运算符声明为非成员友元函数,让左右两个操作数都能支持隐式类型转换,示例:
friend bool operator!=(const Integer& a, const Integer& b) { std::cout << "!="; return a.x != b.x; } friend bool operator==(const Integer& a, const Integer& b) { std::cout << "=="; return a.x == b.x; } - C++20及以后版本,只需要实现
operator==即可,编译器会自动生成正确的!=逻辑,同时自动处理操作数顺序的对称转换,不需要额外写operator!=。
内容的提问来源于stack exchange,提问作者nvhrw
相关产品推荐
相关产品推荐

