C++运算符重载

C++ operator overloading

本文关键字:重载 运算符 C++      更新时间:2023-10-16

为什么下面的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创建此临时数据反过来需要调用再次接受intBase的转换构造,该构造负责将第二个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上使用+的方法。 由于您没有覆盖 Baseoperator+,因此会为等式的每一侧调用转换为 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+objint,因为您没有超载operator +

最后一个 A 来自obj =生成的 intobj 的转换。