C++编译器是如何查找并匹配运算符重载函数的?
关于C++中
ostream& operator<<重载的放置规则与查找逻辑 1. 这类运算符重载不能随意放置,仅支持两类合法位置
- 作为全局非成员函数,放在
Date类所属的同一命名空间下:这是最普遍的实现方式,你给出的代码示例就属于这类。需要注意的是,该函数的声明必须出现在调用位置之前,否则会触发编译错误,因此通常我们会将函数声明写在Date类的头文件中,具体实现放在对应的源文件内。 - 作为
Date类的友元函数直接定义在类内部:这种写法等价于在Date类所属的同一命名空间下声明了该全局函数,调用规则和第一种完全一致。
禁止放置的位置:不能作为
Date类的成员函数(成员函数的第一个隐含参数是this指针,会要求左操作数为Date对象,不符合cout << date的使用习惯);也不能放在与Date类、std命名空间无关的其他命名空间下,否则查找逻辑无法定位到该函数。
2. C++对该运算符的查找、编译、调用流程
C++对运算符重载的查找遵循**实参依赖查找(ADL,又称Koenig查找)**规则,具体执行流程如下:
- 当编译器遇到
cout << date_obj这类表达式时,会先将其转换为等价的函数调用形式operator<<(cout, date_obj) - 第一步执行普通名字查找:在当前作用域、外层作用域遍历所有名为
operator<<的函数,筛选出参数数量匹配的候选函数 - 第二步触发ADL查找:自动到两个实参所属的命名空间中继续查找候选,一个是
cout所属的std命名空间,另一个是date_obj所属的Date类的命名空间,这也是要求将重载放在Date类同命名空间下的核心原因 - 对所有候选函数执行重载决议:匹配参数类型,选出最合适的重载,如果你定义的重载第二个参数为
const Date&,刚好和传入的Date对象类型匹配,就会被选中 - 最后编译器会校验选中函数的返回值类型,你定义的函数返回
ostream&,刚好支持cout << a << b这类链式调用,完全符合语法要求,即可正常编译生成对应的函数调用代码
如果该重载的声明没有出现在调用位置之前,哪怕你在其他源文件中实现了该函数,编译阶段也会因找不到匹配的候选函数报错,不会等到链接阶段再处理。
内容的提问来源于stack exchange,提问作者Joe Smith
相关产品推荐
相关产品推荐

