26

乡亲

我遇到了许多线程来理解多态性(编译时和运行时)。我很惊讶地看到程序员声称重载是运行时而覆盖是编译时的一些链接。

我想从这里知道的是:

  1. 带有实时示例和小代码的运行时多态性以及我们应该使用什么场景。
  2. 编译时多态性与实时示例和小代码以及何时使用。

因为我阅读了很多理论定义,但我对理解并不满意。

另外,我想到了,我也觉得,重载应该是运行时的,因为,假设我有一个计算面积的方法,在运行时它只根据我传递的参数决定调用哪个重载方法(假设我只传递一个参数,它应该触发 Square,如果参数是 2,它应该触发 Rectangle)....所以我不能声明它的运行时间吗?它的编译时间如何?(理论上大多数人说,重载是编译时间,但他们甚至没有给出正确的实时示例......很少有人声称它的运行时间)......

另外,我觉得最重要的是编译时间,因为当你编写代码和编译时,你确保你使用了 virtual 关键字并在派生类中覆盖了该方法,否则会给你编译时间错误。所以我感觉到它的编译时间,就像我在线程中看到的那样......但是大多数线程声称它的运行时:D

我很困惑 :( 这个问题是我的问题 1 和 2 的补充。请提供一个实时示例.. 因为我已经知道理论定义.. :(

谢谢....

4

3 回答 3

29

在重载的情况下,您使用的是静态(编译时)多态性,因为编译器确切地知道您正在调用哪个方法。例如:

public static class test
{
    static void Main(string[] args)
    {
        Foo();
        Foo("test");
    }

    public static void Foo()
    {
        Console.WriteLine("No message supplied");
    }

    public static void Foo(string message)
    {
        Console.WriteLine(message);
    }
}

在这种情况下,编译器根据参数的数量/类型准确地知道我们正在调用哪个 Foo() 方法。

覆盖是动态(运行时)多态性的一个例子。这是因为编译器不一定知道在编译时传入的是什么类型的对象。假设您在库中有以下类:

public static class MessagePrinter
{
    public static void PrintMessage(IMessage message)
    {
        Console.WriteLine(message.GetMessage());
    }
}

public interface IMessage
{
    public string GetMessage();
}

public class XMLMessage : IMessage
{
    public string GetMessage()
    {
        return "This is an XML Message";
    }
}

public class SOAPMessage : IMessage
{
    public string GetMessage()
    {
        return "This is a SOAP Message";
    }
}

在编译时,您不知道该函数的调用者是否传递了 XMLMessage、SOAPMessage 或可能在其他地方定义的另一种类型的 IMessage。当调用 PrintMessage() 函数时,它会根据传入的 IMessage 类型确定在运行时使用哪个版本的 GetMessage()。

于 2012-06-06T14:17:41.770 回答
5

阅读:多态性(C# 编程指南)

类似的答案:编译时和运行时多态性

好吧,有两种类型的多态性,如下所述:

  • 静态多态性(早期绑定)
  • 动态多态性(后期绑定)

静态多态性(早期绑定):

静态多态性也称为早期绑定和编译时多态性。方法重载和运算符重载是相同的示例。

它被称为早期绑定,因为编译器知道具有相同名称的函数,并且在编译时也知道要调用哪个重载函数。

例如:

public class Test
{
    public Test()
    {

    }

    public int add(int no1, int no2)
    {

    }

    public int add(int no1, int no2, int no3)

    {

    }
}

class Program
{
    static void Main(string[] args)
    {
        Test tst = new Test();
        int sum = tst.add(10, 20);

        // here in above statement compiler is aware at compile time that need to call function add(int no1, int no2), hence it is called early binding and it is fixed so called static binding.
    }
}

动态多态性(后期绑定):

public class Animal
{
    public virtual void MakeSound()
    {
        Console.WriteLine("Animal sound");
    }
}

public class Dog:Animal
{
    public override void MakeSound()
    {
        Console.WriteLine("Dog sound");
    }
}

class Program
{
    static void Main(string[] args)
    {
        Animal an = new Dog();
        an.MakeSound();           
        Console.ReadLine();
    }
}

和上面的代码一样,任何其他对虚拟方法的调用,都会被编译成一个 callvirt IL 指令。这意味着被调用的实际方法是在运行时确定的(除非 JIT 可以优化某些特殊情况),但是编译器检查了该方法是否存在,它选择了最合适的重载(如果有的话)并且它有保证函数指针将存在于该类型的 vtable 中明确定义的位置(即使这是一个实现细节)。解决虚拟调用的过程非常快(您只需要取消引用几个指针),因此没有太大区别。

于 2012-06-06T14:06:52.897 回答
0
public class Animal {
    public virtual void MakeSound()
    {
        Console.WriteLine("Animal sound");
    } }

public class Dog:Animal {
    public override void MakeSound()
    {
        Console.WriteLine("Dog sound");
    } }

class Program {
    static void Main(string[] args)
    {
        Animal an = new Dog();
        an.MakeSound();           
        Console.ReadLine();
    } }

这是动态多态性,因为在运行时决定哪个版本的 MakeSound 将被调用父或子,因为子可能不会覆盖父函数或可能会覆盖它,但这一切都是在运行时决定的,哪个版本叫做 ....

于 2016-08-27T10:33:17.767 回答