C++运算符重载
C++ operator overloading
为什么下面的C++程序输出"ACCA"?为什么operator int()
叫两次?
#include "stdafx.h"
#include <iostream>
using namespace std;
class Base {
public:
Base(int m_var=1):i(m_var){
cout<<"A";
}
Base(Base& Base){
cout<<"B";
i=Base.i;
}
operator int() {
cout<<"C";
return i;
}
private:
int i;
};
int main()
{
Base obj;
obj = obj+obj;
return 0;
}
首先,这一行:
Base obj;
默认构造对象obj
,方法是选取接受整数的构造函数,默认值为 1
。这是第一个A
打印到标准输出的原因。
然后,这个表达式:
obj + obj
需要选择可行的超载operator +
。在这种情况下,由于obj
具有用户定义的int
转换,因此将选取内置operator +
,并且两个参数都转换为int
。这是将两个C
打印到标准输出的原因。
然后,要obj
的作业:
obj = obj + obj
需要为Base
调用隐式生成的operator =
。隐式生成的operator =
具有签名:
Base& operator = (Base const&);
这意味着等号右侧的表达式(类型为 int
(必须转换为从中分配obj
的临时Base
对象(隐式生成的operator =
的引用参数绑定到此临时对象(。
但是,从int
创建此临时数据反过来需要调用再次接受int
的Base
的转换构造,该构造负责将第二个A
打印到标准输出。
operator int()
被调用两次,因为你没有重载operator+
。编译器不知道如何将Base
添加到Base
,因此它们被转换为int
(因为您教了它如何做到这一点(,它确实知道如何做。以下代码打印ADA
:
#include <iostream>
using namespace std;
class Base {
public:
Base(int m_var=1):i(m_var){
cout<<"A";
}
Base(Base& Base){
cout<<"B";
i=Base.i;
}
operator int() {
cout<<"C";
return i;
}
int operator+(Base& Base)
{
cout<<"D";
return i+Base.i;
}
private:
int i;
};
int main()
{
Base obj;
obj = obj+obj;
return 0;
}
构造对象时,得到第一个"A":
Base obj;
当你指定添加obj+obj
时,编译器需要找出一种在obj
上使用+
的方法。 由于您没有覆盖 Base
的operator+
,因此会为等式的每一侧调用转换为 int()
:
obj+obj
这将打印"CC"
.
然后,你赋值给 obj
的类型为 Base
,因此运行可以接受 int ( 来自 int()
运算符的 i + i
(的构造函数,它打印 "A":
obj = obj+obj; // Assignment prints "A"
obj = obj+obj;
^^^--------obj converted to int here
^^^----obj converted to int here
^^^^^------------Base(int) ctor and default operator= called here
超载铸造操作员通常不是一个好主意,除非您了解成本并知道在特定情况下的好处大于它们。
下面的程序C++如何计算为"ACCA"?
显示的第一个字母是"A"。此输出与此行相关:
Base obj;
。在其中创建 Base 的新实例。
下一行有点复杂:
obj = obj+obj;
通常,这被翻译成 obj.operator+( obj )
,但是您在类 Base
中没有运算符 + 重载,因此此翻译无效。剩下的可能性是运算符 + 实际上是数字加法运算符。
是的,这是可能的,因为您已经为int
提供了演员表 .因此,可以在int
中转换方程的每个项...因此operator int
被称为两次。调用operator int
的实际次数取决于激活的优化。例如,编译器可以意识到这两个术语是相同的,然后在第一次调用operator int
后创建一个新的临时术语。在这种情况下,您将看到 CA 而不是 CC。
最后,执行赋值表达式obj.operator=( temp )
。这里的关键词是临时。为了使默认operator=
正常工作,由于它没有重载,因此右侧必须有一个Base
对象。实际上可以拥有它,因为Base
使用int
来构建新实例。好的,所以obj + obj
的结果是一个int
(比如它被称为"x"(数字,编译器创建了一个类 Base
的临时对象,该对象由数字 x 构造,因为执行了以下行:
Base temp( x );
这就是看到的最后一个字母是"A"的方式。同样,许多编译器可以避免在某些情况下构建临时文件,因此可能看不到末尾的"A"。
请注意,此行:
obj = obj + obj
因此分解为:
int x = ( (int) obj ) + ( (int) obj );
Base temp( x );
obj = temp;
最后一条指令的结果是,obj
所在的内存将被temp
的内容占用(这是默认复制构造函数的角色,它为类的每个成员执行operator=
,再次参见"三法则"(。
如您所见,运算符重载涉及许多问题,如果您对该语言没有或多或少的深入了解,这些问题可能无法预见。还要考虑到像Java这样的语言完全阻止了它的使用,而C#从受控的角度允许它。
你在表达式 obj+obj
中引用 obj 两次,每个这样的引用都必须转换为整数。
这样的转换可能是"有状态的"并非不可能(尽管这是一个可怕的想法( - 也就是说,它可以通过设计在每次调用时返回不同的值。毕竟,obj
表示的值可能会改变(它可能是计数器或类似的东西(。因此,编译器必须为每个引用重新评估它。
每个操作数调用一次,是否是同一实例并不重要。
obj = obj+obj;
它将第一个操作数"强制转换"为 int,然后是第二个操作数。
如果要避免此隐式强制转换,则需要重载运算符 +。
它调用operator int()
两次,因为它需要先将 obj 转换为 int,然后才能添加它们。
第一个 A 来自
Base obj;
这两个 C 来自将 obj 转换为 obj+obj
到 int
,因为您没有超载operator +
。
最后一个 A 来自obj =
生成的 int
到 obj
的转换。
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 重载运算符new[]的行为取决于析构函数
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- 在 myVector 类中重载运算符 + 时出错
- 为什么常量词在重载运算符中不与 ostream 对象一起使用<<?
- 如何在 cpp 中重载运算符 +=?
- C++ 如何重载 [] 运算符并进行函数调用
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 重载运算符有地址吗?
- 如何迭代重载运算符 [] 的类?
- 重载运算符与添加问题
- 模板基类中的重载运算符
- 如何调用用于重载运算符"<<"的 friend 函数?
- 在 C++17 中的命名空间和子命名空间中重载运算符是不明确的
- 重载运算符<<采用谷歌 C++ 风格
- C++ 如何正确重载 + 运算符
- cout (<<) 重载运算符不打印减去的矩阵
- 如何在 c++ 中重载运算符 + 以便能够 whrite c_str = "smth" + c_str;
- 重载运算符*以获取对另一个类的实例的引用