当存在转换成员函数时,编译器为何允许引用转换为void*?
为什么类引用能通过转换运算符用于条件判断?
先回顾一下问题中的代码:
#include <iostream> struct A { operator void* (){ return nullptr; } }; A a; A& getA () { return a; } int main(int, char**) { int x = 0; // this works if (std::cout << x) { return 1; } // this works only because we have operator void* defined if (getA()) { return 2; } return 0; }
核心原因其实很简单——C++里的引用就是它绑定对象的别名,在绝大多数场景下,使用引用和直接操作原对象完全等价。
当你写if (getA())时,getA()返回的A&会被编译器当作它所绑定的A对象本身来处理。这时候条件判断需要一个能转换成布尔值的表达式,而C++的规则允许通过用户定义的转换运算符(比如你定义的operator void*()),把类对象(或其引用)转换成可用于条件判断的类型。
具体的执行流程是这样的:
- 编译器看到
if (getA()),需要将A&转换成适合条件判断的类型; - 它会查找
A类中定义的转换运算符,找到了operator void*(); - 因为引用可以直接调用对象的成员函数(包括转换运算符),所以编译器会调用这个函数,把引用绑定的
A对象转换成void*; - C++允许指针类型(包括
void*)用于条件判断:如果指针是空指针(比如你这里返回的nullptr),条件为假;否则为真。
你代码里的std::cout << x能工作也是同样的道理:std::ostream的operator<<返回ostream&,而ostream类(C++11之前)也定义了operator void*(),引用被当作对象本身调用转换运算符,从而能用于条件判断。
顺便提一句:C++11之后更推荐使用explicit operator bool()来实现这种转换,因为operator void*()可能会导致一些意外的隐式转换(比如不小心把对象当作指针做算术运算),而explicit修饰的转换运算符只会在直接需要布尔值的场景(比如if、while条件)下被触发,安全性更高。
内容的提问来源于stack exchange,提问作者Kobi
相关产品推荐
相关产品推荐

