编译时间多态性与运行时多态性
为什么重载称为编译时多态和覆盖C#中的运行时多态?
重写函数是具有相同签名的函数,但是在不同的派生类中实现。 在编译时,通常基类类型用于引用对象,但在运行时此对象可以是派生类型,因此当调用重写方法时,调用的实现依赖于什么类型的对象是执行在编译时未知的调用(基本类型与派生类型)。
重载(不是真正的多态)只是具有相同名称但签名不同的多个函数(对于使用不同数量的参数的对象,请考虑多个构造函数)。 调用哪个方法在编译时是已知的,因为此时指定了参数。
好吧,重载决策(使用哪个方法签名 ,基于参数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); } }
这里调用了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(); } }
这里x
的编译时类型是Base
,但它仍然是被调用的派生类的重写方法,因为x
引用的对象的执行时类型是Derived
。
1由于方法隐藏等原因,它实际上稍微复杂一些 – 但在简单的情况下,您可以将其视为仅仅选择签名。
多态性
通过inheritance,一个类可以用作多种类型; 它可以用作自己的类型,任何基类型,或任何接口类型,如果它实现接口。 这称为多态性。
多态性意味着具有多种forms。 重载和重写用于实现多态。 多态性分为编译时多态或早期绑定或静态绑定和运行时多态或后期绑定或动态绑定。
覆盖 – 在类及其子类中具有相同参数和相同返回类型的相同方法名称。 覆盖C#使用“override”关键字。 覆盖方法意味着用新的数据处理方式替换它。
重载 – 具有不同参数的相同方法名称,可能是也可能不是同一类本身写入的返回类型。
编译时间多态性或早期绑定
编译器识别它在编译时必须执行哪种多态forms的多态,称为编译时多态或早期绑定。
早期绑定的优点是执行速度很快。 因为编译期间编译器知道关于该方法的所有事情,所以缺点是缺乏灵活性。
早期绑定的示例是重载方法,重载运算符和使用派生对象直接调用的重写方法。
运行时多态性或后期绑定
编译器识别在运行时而不是在编译时执行哪种多态forms的多态性称为运行时多态或后期绑定。
后期绑定的优点是灵活性和缺点是执行将很慢,因为编译器必须获得有关在运行时执行的方法的信息。
后期绑定的示例是使用基类对象调用的重写方法。
class A { public virtual void Leg(string Name) { } } class B:A { public override void Leg(string Name) { } }
过载的示例
class A { void a() { } void a(string Name) { } }
换句话说,“单个对象的许多forms称为多态”。
例如:
团队负责人表现为Sub Ordinate。 团队负责人对他/她的老年人表现出色。 团队负责人对其他团队领导表现出色。
团队领导是一个对象,但在不同的情况下态度是不同的。
方法覆盖与方法隐藏之间的区别
方法重写允许子类提供已由基类提供的方法的特定实现。 子类中的实现覆盖(替换)基类中的实现。 要记住重写的重要一点是,执行重写的方法与基类中的方法有关。 在引用上调用虚方法时,引用所引用的对象的实际类型用于确定应使用哪个方法实现。 在派生类(子类)中重写基类的方法时,将使用派生类中定义的版本。 即使调用应用程序不知道该对象是派生类的实例,也是如此。
方法隐藏在基类和派生类中的方法之间没有关系。 派生类中的方法隐藏基类中的方法。
编译时多态
假设你说你有两种方法如下; 因为该方法具有相同的名称但具有不同的参数; 它被称为“重载”方法。 吃(串食); 吃(串食物,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); } }
现在,当您编译此程序时,编译器确切地知道在编译期间要调用哪个版本的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" } }
在上面的代码中, x是chimp类型。 即使编译器认为它将在黑猩猩中调用walk方法; 但这不是实际发生的事情 。 由于它依赖于CLR(运行时),这种多态性被称为“运行时”多态。
多态性
多态性意味着许多forms(能够采取多种forms)。 在多态性中,poly表示“多个”,而变体表示“forms”,因此多态性意味着许多forms。
在多态性中,我们将在相同的类中声明具有相同名称和不同参数的方法,或者在不同的类中使用相同的名称和相同的参数。 多态性能够提供使用相同名称实现的方法的不同实现。
在多态性中,我们有两种不同的类型
- Compile Time Polymorphism (Called as Early Binding or Overloading or static binding) - Run Time Polymorphism (Called as Late Binding or Overriding or dynamic binding)
编译时间多态性
编译时多态意味着我们将声明具有相同名称但签名不同的方法,因此我们将使用相同的方法名执行不同的任务。 这个编译时多态也称为早期绑定或方法重载。
方法重载或编译时多态意味着具有不同签名(不同参数)的相同方法名称
有关更多详细信息,请在c#中检查此链接多态性
运行时多态性
运行时多态性也称为后期绑定或方法覆盖或动态多态。 运行时多态或方法重写意味着具有相同签名的相同方法名称。
在此运行时多态或方法重写中,我们可以通过在派生类中创建类似函数来覆盖基类中的方法,这可以通过使用inheritance原则并使用“虚拟和覆盖”关键字来实现。
它称为运行时多态,因为行为是在运行时决定的,而不是编译时。
当您调用objectVariable.Method()之类的方法时,您的机器将调用哪个方法将取决于objectVariable中存在哪个类实例,并且在您为其分配类的实例后决定该实例。 这将在运行时发生,而不是在编译时发生。 因此名称为“运行时多态”。
您可以在以下位置阅读更多信息: 编译时和运行时多态之间有什么区别
c#中的运行时多态性示例。
using System; public class demo{ public static void Main(String[] args){ cal cal ; add a = new add(); cal = a; Console.WriteLine("Addition is" + cal.calculate(20, 20)); sub s = new sub(); cal = s; Console.WriteLine("Substraction is" + cal.calculate(20, 20)); mul m = new mul(); cal = m; Console.WriteLine("Multiplication is" + cal.calculate(20, 20)); div d = new div(); cal = d; Console.WriteLine("Division is" + cal.calculate(20, 20)); Console.ReadLine(); } } public abstract class cal{ public abstract int calculate(int a, int b); } public class add : cal { public override int calculate(int a ,int b){ return a+b; } } public class sub : cal{ public override int calculate(int a, int b){ return ab; } } public class mul : cal{ public override int calculate(int a, int b){ return a*b; } } public class div : cal{ public override int calculate(int a, int b){ return a/b; } }
因为在编译时已经知道调用了哪些重载函数,但对于重写函数并不总是如此。
静态多面体的经典示例基于模板元编程或Duck Typing,但不基于方法重载。
静态多面体意味着desicion是由compilier(静态)完成的,而动态polimorphism意味着desition只在运行时(动态)进行。
编译时间多态性
编译时多态性也称为方法重载。 方法重载意味着具有两个或多个具有相同名称但具有不同签名的方法。
运行时多态性
运行时多态性也称为方法覆盖。 方法覆盖意味着具有两个或多个具有相同名称和相同签名但具有不同实现的方法
- 如何获取使用SynchronizationContext的任务? 那么SynchronizationContext是如何使用的呢?
- 当Button失去OnClick时,Unity缺少警告
- 用于提取String的某些部分的正则表达式
- CamelCasePropertyNamesContractResolver在MapHttpRoute之后无法正常工作
- 在C#中从MySQL中检索LONGBLOB
- 如何使用来自其他来源的数据更新SQL Server表(DataTable)
- 获取当前的ViewModel MvvmCross
- 当DataSource是BindingList时过滤BindingSource
- EF – 在HTTP请求期间创建模型exception时,不能使用上下文