增加运算符重载

我在尝试重载C#中的后增量运算符时遇到问题。 使用整数我们得到以下结果。

int n;

n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(n++); // 10
Console.WriteLine(n); // 11

n = 10;
Console.WriteLine(n); // 10
Console.WriteLine(++n); // 11
Console.WriteLine(n); // 11

但是,当我尝试使用类时,它看起来像交换了对象。

class Account
{
    public int Balance { get; set; }
    public string Name { get; set; }

    public Account(string name, int balance)
    {
        Balance = balance;
        Name = name;
    }

    public override string ToString()
    {
        return Name + " " + Balance.ToString();
    }

    public static Account operator ++(Account a)
    {
        Account b = new Account("operator ++", a.Balance);
        a.Balance += 1;
        return b;
    }

    public static void Main()
    {
        Account a = new Account("original", 10);

        Console.WriteLine(a); // "original 10"

        Account b = a++;

        Console.WriteLine(b); // "original 11", expected "operator ++ 10"
        Console.WriteLine(a); // "operator ++ 10", expected "original 11"
    }
}

调试应用程序,重载操作符方法,返回具有旧值(10)的新对象和通过引用传递的对象,具有新值(11),但最终交换对象。 这是为什么发生?


关键在于理解Account b = a++;这一行Account b = a++; 作品。 鉴于您的代码是如何编写的,该行与此相当:

Account b = a;
a++;

这是它将执行的顺序。有效的分配(1)发生在增量之前。 所以,这条线的第一个效果是a和b都指的是原始对象a。

现在将评估++部分。 在运算符方法内部,我们增加原始对象的Balance 。 在这一点上,a和b都指向原始值, Balance为11,b将继续这样做。

但是,您已在运算符方法内创建了一个新对象,并将其作为运算符的输出返回。 现在将更新一个指向新创建的对象。

所以,现在a指向一个新对象,而b继续指向原始对象。 这就是WriteLine输出出现交换的原因。

正如@MarkusQ指出的那样,++运算符是为了做就地修改。 通过生成一个新的对象,你打破了这个假设。 运算符在对象上的重载是一个棘手的问题,这是一个很好的例子,为什么它在大多数情况下更好地避免。


1 - 出于准确性的考虑,在处理运算符对象时,赋值并不实际发生在增量之前,但最终结果在这种情况下是相同的。 实际上,原始对象参考被复制,操作在原稿上执行,然后复制的参考被分配给左侧变量。 如果你假装第一个任务发生,那就更容易解释了。

真正发生的是这样的:

Account b = a++;

结果是,由于++运算符如何处理对象:

Account copy = a;

Account x = new Account("operator ++", a.Balance);
a.Balance += 1; // original object's Balance is incremented
a = x; // a now points to the new object, copy still points to the original

Account b = copy; // b and copy now point at the same, original, object

我的第一个想法是指出++的正常语义是就地修改。 如果你想模仿你会写:

public static Account operator ++(Account a)
{
    a.Balance += 1;
    return a;
}

而不是创建一个新的对象。

但后来我意识到你正在试图模仿后期增量。

所以我的第二个想法是“不这样做” - 语义不能很好地映射到对象上,因为被“使用”的值实际上是一个可变的存储位置。 但没有人喜欢被陌生人告知“不要那么做”,所以我会让微软告诉你不要这样做。 我担心他们的话在这些问题上是最终的。

PS至于为什么它正在做它的功能,你真的重写预增量运算符,然后像使用后增量运算符一样使用它。


您应该始终返回更改的值。 C#使用此值作为新值,并返回适合操作员的旧值或新值。

链接地址: http://www.djcxy.com/p/73139.html

上一篇: increment Operator Overloading

下一篇: overloading the << operator in c++