编译时间多态性与运行时多态性

Sau*_*abh 34 c# oop

为什么重载称为编译时多态和覆盖C#中的运行时多态?

Jon*_*eet 35

好吧,重载决策(使用哪个方法签名,基于参数1)是由编译器完成的,而重写决策(使用哪种方法实现,基于方法的目标类型)由CLR在执行时间处理时间.

我不会经常称过载"多态".根据我的经验,这个词通常指的是压倒一切.我认为重载确实允许你将一种类型的对象视为另一种类型,尽管重载本身并不需要涉及 - 这只是普通的类型转换.

这是一个示例,显示在编译时执行重载选择:

using System;

class Test
{
    static void Foo(object a)
    {
        Console.WriteLine("Object overload called");
    }

    static void Foo(string a)
    {
        Console.WriteLine("String overload called");
    }

    static void Main()
    {
        object x = "hello";
        Foo(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

这里Foo(object)调用了重载,因为在编译时x是类型的object- 只有在执行时才知道它引用了一个字符串.

与此示例比较:

using System;

class Base
{
    public virtual void Foo()
    {
        Console.WriteLine("Base.Foo called");
    }
}

class Derived : Base
{
    public override void Foo()
    {
        Console.WriteLine("Derived.Foo called");
    }
}

class Test
{
    static void Main()
    {
        Base x = new Derived();
        x.Foo();
    }
}
Run Code Online (Sandbox Code Playgroud)

这里的编译时类型xBase,但它仍然是被调用的派生类的重写方法,因为引用的对象的执行时类型xDerived.


1由于方法隐藏等原因,它实际上稍微复杂一些 - 但在简单的情况下,您可以将其视为仅仅选择签名.


Nat*_*ich 22

重写函数是具有相同签名的函数,但是在不同的派生类中实现.在编译时,通常基类类型用于引用对象,但在运行时此对象可以是派生类型,因此当调用重写方法时,调用的实现取决于对象的类型执行在编译时未知的调用(基本类型与派生类型).

重载(不是真正的多态)只是具有相同名称但签名不同的多个函数(对于使用不同数量的参数的对象,请考虑多个构造函数).调用哪个方法在编译时是已知的,因为此时指定了参数.

  • 重载为何不是真正的多态 (3认同)

Jom*_*rge 9

多态性

通过继承,一个类可以用作多种类型; 它可以用作自己的类型,任何基类型,或任何接口类型,如果它实现接口.这称为多态性.

多态性意味着具有多种形式.重载和重写用于实现多态性.多态性分为编译时多态或早期绑定或静态绑定和运行时多态或后期绑定或动态绑定.

覆盖 - 在类及其子类中具有相同参数和相同返回类型的相同方法名称.覆盖C#使用"override"关键字.覆盖方法意味着用新的数据处理方式替换它.

重载 - 具有不同参数的相同方法名称,可能是也可能不是同一类本身写入的返回类型.

编译时间多态性或早期绑定

编译器识别在编译时必须执行哪种多态形式的多态,称为编译时多态或早期绑定.

早期绑定的优点是执行速度很快.因为在编译期间编译器知道关于该方法的所有事情,所以自身和缺点是缺乏灵活性.

早期绑定的示例是重载方法,重载运算符和通过使用派生对象直接调用的重写方法.

运行时多态性或后期绑定

编译器识别在运行时而不是在编译时执行哪种多态形式的多态性称为运行时多态或后期绑定.

后期绑定的优点是灵活性和缺点是执行将会很慢,因为编译器必须获取有关在运行时执行的方法的信息.

后期绑定的示例是使用基类对象调用的重写方法.

 class A
 {
    public virtual void Leg(string Name)
    {

    }
 }

 class B:A
 {
    public override void Leg(string Name)
    {

    }
 }
Run Code Online (Sandbox Code Playgroud)

过载的示例

 class A
 {
  void a()
   {
   }
  void a(string Name)
   {
   }
 }
Run Code Online (Sandbox Code Playgroud)

换句话说,"单个对象的许多形式称为多态".

例如:

团队负责人表现为Sub Ordinate.团队负责人对他/她的老年人表现出色.团队负责人对其他团队领导表现出色.

团队领导是一个对象,但在不同的情况下态度是不同的.

方法覆盖与方法隐藏之间的区别

方法重写允许子类提供已由基类提供的方法的特定实现.子类中的实现覆盖(替换)基类中的实现.要记住重写的重要一点是,执行重写的方法与基类中的方法有关.在引用上调用虚方法时,引用所引用的对象的实际类型用于确定应使用哪个方法实现.在派生类(子类)中重写基类的方法时,将使用派生类中定义的版本.即使调用应用程序不知道该对象是派​​生类的实例,也是如此.

方法隐藏在基类和派生类中的方法之间没有关系.派生类中的方法隐藏基类中的方法.


小智 6

编译时多态

假设你说你有两种方法如下; 因为该方法具有相同的名称但具有不同的参数; 它被称为"重载"方法.吃(串食); 吃(串食物,SpoonOrFork);

而你在晚餐课上使用这样的东西

public class Man
{
 public bool Eat (string food)
 {
  //implementation
 }

 public bool Eat (string food, string SpoonOrFork)
 {
  //implementation
 }

}
public class dinner
{
  public bool Start()
  {
   string food = "course1";
   Man.Eat ( food);
  }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您编译此程序时,编译器确切地知道在编译期间要调用哪个版本的Eat方法(因为参数不同).

这就是为什么它被称为编译时多态.

运行时多态性

public class chimp
    {
        public virtual void walk()
        {
            Console.WriteLine("I am walking using 4 legs");
        }

    }

    public class neanderthals : chimp
    {
        public override void walk()
        {
            Console.WriteLine("I am walking using 2 legs");
        }

    }



    class Program
    {
        static void Main(string[] args)
        {
            chimp x = new neanderthals();
            x.walk();
            Console.ReadLine(); // this will give an output of "I am walking using 2 legs"
        }
    }
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,xchimp类型.即使编译器认为它将在黑猩猩中调用walk方法; 但这不是实际发生的事情.由于它依赖于CLR(运行时),这种多态性被称为"运行时"多态.