c++ - C++ 重载解析查询
问题描述
为任何失礼道歉,这是我在任何此类论坛上的第一篇文章。
下面的代码是一些实验的结果,运行时的输出让我感到惊讶,即
Inside char ch
Inside MyChar ch
我的问题是为什么?更准确地说,为什么编译器会通过首先将 MyChar.get 返回的值转换为 char 然后调用来解决对 Process 的调用
void Process(char ch)
而不仅仅是打电话
void Process(MyChar &ch)
如果
MyChar.operator char()
然后从 MyChar 的定义中删除
void Process(MyChar &ch)
像我预期的那样被调用。
我正在使用 MS Visual C++ 2008 进行编译。
这可能是一个众所周知的现象,但我的搜索尝试未能发现任何有用的信息。
非常感谢,史蒂夫。
class MyChar
{
public:
MyChar(){m_ch=1;};
MyChar(char ch){m_ch=ch;};
~MyChar(){};
char m_ch;
operator char(){return m_ch;};
MyChar get(){return *this;};
};
void Process(MyChar &ch);
void Process(char ch);
int main()
{
MyChar Test;
Process(Test.get());
return 0;
}
void Process(MyChar &ch)
{
printf("\nInside MyChar ch");
}
void Process(char ch)
{
printf("\nInside char ch");
MyChar chch(ch);
Process(chch);
}
解决方案
VS 2008 现在已经很老了,而且并不以其出色的标准合规性而闻名。一般来说,期待一些奇怪的行为。请参阅@IgorTandetnik 的评论:与 C++ 语言规则相反,VS 2008 有时允许您将临时对象绑定到非 const 左值引用。
以下是正在发生的事情的细分:
Test.get()
返回对象的副本Test
。这是一个临时的,因为你直接将它传递给Process()
(简而言之,如果它没有名称,它是一个临时的)。- 现在第一个重载决议开始了。
Process(MyChar&)
将是关于类型的最接近的匹配,但它不合适,因为只有const左值引用可以绑定到临时。但是MyChar
有一个到 char 的隐式转换,所以下一个最好的重载是Process(char)
, 被选中。 - 第二次
Process()
调用触发另一个重载决议。你用MyChar
左值调用它chch
。AMyChar&
可以绑定到MyChar
左值没问题。因为相同的类型Process(MyChar&)
是最好的匹配并被选中。Process(char)
也是一个候选,但因为它涉及类型转换,所以它是一个更糟糕的匹配。
到目前为止,一切都很好。VS 2008 的行为完全符合标准的预期和要求。现在,当您删除隐式转换时,VS 2008 的非标准行为开始生效。Process(char)
不再是可以调用的有效函数,因此仅Process(MyChar&)
保留为候选函数并被选中。
但是,如果您完全担心交叉编译器的兼容性,则不能依赖它。例如,对于 GCC 7.3,您的代码的 no-conversion-operator 版本将无法编译:
错误:无法将“MyChar&”类型的非常量左值引用绑定到“MyChar”类型的右值</p>
Clang 给出了类似的错误消息。实现所需行为的标准符合方法是将const添加到Process
函数的签名中:
Process(const MyChar&)
或不通过临时:
MyChar Test;
MyChar AnotherChar = Test.get();
Process(AnotherChar);
推荐阅读
- swiftui - 如何更改特定区域的工作表 DragGesture?
- typescript - 是否可以在同一个文件中多次使用“require”?
- angular - 尝试将 razorpay 与 angular9 集成时无法读取 null 的属性 postMessage
- c# - 有没有办法通过隐式转换在类实例中设置参数,就像 c# 中的运算符一样?
- pyqt - 如何在 python、PyQt 中读取文件/读取?
- angular - 如何刷新 MatTable 中的数据源?
- memory-management - 远程 Peer 如何处理 RDMA 写操作发送的数据
- c# - ASP .NET Core DI:向 HTTP 客户端提供异步 BaseAddress
- html - Bootstrap 4在手风琴面板中保持打开其他面板
- python - 从 dataframe.groupby() 将参数传递给 lambda 函数