【问题标题】:In overloading why the return type of the function is not considered? [duplicate]在重载时为什么不考虑函数的返回类型? [复制]
【发布时间】:2011-05-20 21:49:07
【问题描述】:

可能重复:
Function overloading by return type?

嗨,

在重载中,我们说参数列表必须按数量或类型不同,但返回类型无关紧要,为什么会这样???

功能

//Function 1
int Add(int a, int b)
{return a+b;}

//Function 2
Double Add(Double a, Double b)
{return a+b;}

//Function 3
Double Add(int a, int b)
{return (Double)a+b;}

函数 1 2 被重载,而函数 1 和 3 不是 ???原因???

非常感谢任何帮助。

【问题讨论】:

标签: c# .net c++ oop


【解决方案1】:

编译器需要在编译时知道你试图调用哪个函数。如果它们仅在返回类型上有所不同,这通常是不可能的。例如:

var result = Add(1, 2);

Console.WriteLine(Add(1, 2));

编译器无法知道您是要执行函数 1 还是 3。即使您这样做了

double x = Add(1, 2);

编译器不会知道您是 (a) 想要调用函数 3 还是 (b) 调用函数 1 并进行从 int 到 double 的隐式扩展转换。

【讨论】:

    【解决方案2】:

    在很多情况下这种重载是行不通的。这是其中的两个:

    • 你不关心方法的结果,这样调用它:

      Add(3, 4);
      

    这个应该调用方法1还是3?

    • 你使用var来分配结果

      var result = Add(3, 4);
      

    这种重载充其量是模棱两可的,因此是不允许的。

    【讨论】:

      【解决方案3】:

      其他答案涉及为什么,但顺便说一句:在 C# 中,您可以通过使用(滥用?)隐式转换运算符(和延迟)模拟基于返回类型的重载操作):

      using System;
      class Program {
          static void Main() {
              int i = Add(3, 5); // prints: int overload called
              double d = Add(3, 5); // prints: double overload called
          }
          static SuperMagicAdder Add(int a, int b)
          { return new SuperMagicAdder(a, b); }
      }
      struct SuperMagicAdder {
          private readonly int a,b;
          public SuperMagicAdder(int a, int b) { this.a = a; this.b = b; }
          public override string  ToString() { return a + "+" + b; }
          public static implicit operator int (SuperMagicAdder value) {
              Console.WriteLine("int overload called");
              return value.a + value.b;
          }
          public static implicit operator double (SuperMagicAdder value) {
              Console.WriteLine("double overload called");
              return (double)value.a + value.b;
          }
      }
      

      【讨论】:

      • +1。将它与部分类结合起来,你就有了纯粹的邪恶。
      【解决方案4】:

      请注意,有趣的是,C# 中的匿名函数文字 对其结果类型进行了重载,这似乎不会造成任何问题。

      在 C# 中,lambda 可以是两种截然不同的东西:

      • 一段可执行代码(实际上是Delegate 的子类)
      • 操作的抽象表示(基本上是抽象语法树)

      这通过 lambda 字面量的 结果类型 纯粹区别开来:

      Func<int, int> l = (i) => i + i * i;
      

      是一段可执行代码。我可以说

      Console.WriteLine(l(3));
      

      我会得到12

      Expression<Func<int, int>> e = (i) => i + i * i;
      

      是该操作的抽象表示。我可以说

      Console.WriteLine(e);
      

      我会得到的

      i => (i + (i * i))
      

      请注意,这不仅仅是原文。它真的抽象表示的渲染。表达式周围及其内部的额外括号在那里,因为ToString() 对 AST 进行了实际的树遍历并呈现它。 AST 大致如下:

      还有这个

      var v = (i) => i + i * i;
      

      完全是非法的,因为 lambda 在其结果类型上被重载,但 var 关键字说“使用结果类型来确定 v 的类型”。

      【讨论】:

      • 你能举个例子来说明你的意思吗?我无法想象你会如何做这样的事情......
      【解决方案5】:

      允许返回类型作为签名的一部分会在重载解决方案中产生严重的歧义。

      例如,考虑:

      Add(2,3);
      

      我们正在“丢弃”方法返回的值,但是应该调用哪个重载?

      它不适用于隐式类型或将值分配给与任一返回类型兼容的变量。例如:

      var sum = Add(2,3);
      object sum = Add(2,3);
      

      【讨论】:

      • OTOH,如果它被允许,那么这样一个函数的返回值及其类型对调用者来说很重要,所以调用者不会试图使用任何那些模棱两可的调用。您和其他所有人都专注于模棱两可的用途,而忽略了潜在的有效用例。为什么不只在调用确实不明确时才将其设为错误?
      • @visitor:程序员在所有情况下解决歧义是很痛苦的,即告诉编译器绑定哪个方法。想象一下,如果有string Foo(int bar)object Foo(int bar)。现在,假设我们想使用从前一种方法到Func&lt;int, object&gt;(逆变)的方法组转换。这突然变成了一个轻微的头痛。
      猜你喜欢
      • 2011-03-04
      • 2014-04-30
      • 2011-05-18
      • 2013-03-22
      • 1970-01-01
      • 1970-01-01
      • 2015-12-13
      • 2017-06-20
      • 2014-04-09
      相关资源
      最近更新 更多