如何以易于理解的方式描述多态?
我们可以在互联网和图书上找到有关该主题的大量信息,例如 Type polymorphism 。但是,让我们尝试尽可能简单。
答案 0 :(得分:67)
两个对象以不同的行为响应同一个消息;发件人无须照顾。
答案 1 :(得分:32)
带有简单弹出盖的每个罐子都以同样的方式打开。
作为一个人,你知道你可以打开()任何你能找到的东西。
当打开时,并非所有罐头的行为都相同。
一些包含坚果,一些包含假蛇。
结果取决于罐的类型,如果罐是“CanOfNuts”或“CanOfSnakes”,但这与你如何打开它无关。你只知道你可以打开任何Can,并且会得到某种结果,这些结果是根据你打开的Can的类型决定的。
pUnlabledCan->打开(); //可能会给坚果,可能会给蛇。我们不知道,直到我们称之为
Open()的泛型返回类型为“Contents”(或者我们可能决定没有返回类型),因此open始终具有相同的函数签名。
你,人,是用户/来电者
Open()是虚拟/多态函数
“Can”是抽象基类。
CanOfNuts和CanOfSnakes是“Can”类的多态子
每个Can都可以打开,但具体它做什么以及它返回的内容的特定tye是由它可以是什么样的。
当你看到pUnlabledCan时你所知道的就是你可以Open()它,它将返回内容。任何其他行为(例如在你脸上弹出蛇)都由特定的Can决定。
答案 2 :(得分:31)
这是来自我answer的类似问题。这是伪C#/ Java中的多态性的一个例子:
class Animal
{
abstract string MakeNoise ();
}
class Cat : Animal {
string MakeNoise () {
return "Meow";
}
}
class Dog : Animal {
string MakeNoise () {
return "Bark";
}
}
Main () {
Animal animal = Zoo.GetAnimal ();
Console.WriteLine (animal.MakeNoise ());
}
Main()方法不知道动物的类型,并且取决于MakeNoise()方法的特定实现的行为。
答案 3 :(得分:19)
多态的最简单描述是它是一种减少if / switch语句的方法。
它还具有允许您扩展if / switch语句(或其他人的语句)而无需修改现有类的好处。
例如,考虑.NET中的Stream
类。没有多态性,它将是一个单独的大型类,其中每个方法实现一个类似于:
public class Stream
{
public int Read(byte[] buffer, int offset, int count)
{
if (this.mode == "file")
{
// behave like a file stream
}
else if (this.mode == "network")
{
// behave like a network stream
}
else // etc.
}
}
相反,我们允许运行时以更有效的方式为我们进行切换,方法是根据具体类型(FileStream
,NetworkStream
)自动选择实现,例如
public class FileStream : Stream
{
public override int Read(byte[] buffer, int offset, int count)
{
// behave like a file stream
}
}
public class NetworkStream : Stream
{
public override int Read(byte[] buffer, int offset, int count)
{
// behave like a network stream
}
}
答案 4 :(得分:10)
答案 5 :(得分:6)
演员与角色(或角色)
答案 6 :(得分:6)
苹果和橘子都是水果。水果可以吃。因此,苹果和橘子都可以吃。
踢球者?你吃不同的东西!剥橙子,但不剥苹果。
所以实现方式不同,但最终结果是一样的,你吃水果。
答案 7 :(得分:4)
如果它像鸭子一样走路,像鸭子一样嘎嘎叫,那么你可以把鸭子当作鸭子来对待它。
答案 8 :(得分:3)
This is a better article actually
多态性允许对象“看”相同,但行为方式不同。通常的例子是使用Speak()方法获取动物基类,狗子类将发出一个Bark,而Pig子类将发出一个oink。
大多数人使用的5秒简短答案,以便其他开发人员能够了解多态性是否超载和重写
答案 9 :(得分:2)
相同的语法,不同的语义。
答案 10 :(得分:1)
多态性是一种语言功能,允许高级算法代码在多种类型的数据上保持不变。
这是通过确保操作为每种数据类型调用正确的实现来完成的。即使在OOP上下文中(根据此问题的标记),也可以在编译时或运行时解析此“正确实现”(如果您的语言同时支持)。在某些语言(如C ++)中,编译器提供的对运行时多态性(即虚拟分派)的支持特定于OOP,而其他类型的多态也可以对非对象的数据类型(即不是struct
或class
个实例,但可能包含int
或double
等类型。
(C ++支持的多态类型在我的答案中列出并对比:Polymorphism in c++ - 即使您编写其他语言,它也具有潜在的指导意义)
答案 11 :(得分:1)
多态性是通过在它们之间建立共享身份然后利用它来将不同的事物视为相同的事物的能力。
答案 12 :(得分:1)
多态性将世界划分为基于公共属性的框,并且当您只想使用这些公共属性时,将给定框中的项目视为可互换的。
答案 13 :(得分:1)
当同一方法应用于多个类时,您可以获得多态性。例如,String和List都可能具有“Reverse”方法。两种方法都具有相同的名称(“反向”)。两种方法都做了非常相似的事情(反转所有字符或颠倒列表中元素的顺序)。但是每个“反向”方法的实现都是不同的,并且特定于它的类。 (换句话说,String会像字符串一样自行反转,List会像列表一样自行反转。)
要使用比喻,您可以向法国厨师或日本厨师说“做晚餐”。每个人都会以自己独特的方式表演“做晚餐”。
实际结果是你可以创建一个“Reversing Engine”来接受一个对象并在其上调用“Reverse”。只要对象具有反向方法,您的反转引擎就可以工作。
为了扩展厨师的比喻,你可以建立一个“Waiterbot”,告诉厨师“做晚餐”。 Waiterbot不必知道将要制作什么类型的晚餐。它甚至不必确保它与厨师交谈。重要的是,“厨师”(或消防员,或自动售货机,或宠物食品机)知道当它被告知“做晚餐”时该怎么做。
作为程序员,这会给你带来更少的代码行,无论是类型安全还是后期绑定。例如,这是一个类型安全和早期绑定的例子(在我正在编写的类似c语言中):
class BankAccount {
void SubtractMonthlyFee
}
class CheckingAccount : BankAccount {}
class SavingsAccount : BankAccount {}
AssessFee(BankAccount acct) {
// This will work for any class derived from
// BankAccount; even classes that don't exist yet
acct.SubtractMonthlyFee
}
main() {
CheckingAccount chkAcct;
SavingsAccount saveAcct;
// both lines will compile, because both accounts
// derive from "BankAccount". If you try to pass in
// an object that doesn't, it won't compile, EVEN
// if the object has a "SubtractMonthlyFee" method.
AssessFee(chkAcct);
AssessFee(saveAcct);
}
这是一个没有类型安全但具有后期绑定的示例:
class DatabaseConnection {
void ReleaseResources
}
class FileHandle {
void ReleaseResources
}
FreeMemory(Object obj) {
// This will work for any class that has a
// "ReleaseResources" method (assuming all
// classes are ultimately derived from Object.
obj.ReleaseResources
}
main() {
DatabaseConnection dbConn;
FileHandle fh;
// You can pass in anything at all and it will
// compile just fine. But if you pass in an
// object that doesn't have a "ReleaseResources"
// method you'll get a run-time error.
FreeMemory(dbConn);
FreeMemory(fh);
FreeMemory(acct); //FAIL! (but not until run-time)
}
有关一个很好的示例,请查看.NET ToString()方法。所有类都有它,因为所有类都是从Object类派生的。但是每个类都可以以对自己有意义的方式实现ToString()。
编辑:简单!=简短,恕我直言
答案 14 :(得分:1)
多态性是在单个类型的位置存储多种类型的值。
请注意,在我撰写本文时,这个问题的大多数其他答案实际上都是描述动态调度,而不是多态。
Dynamic dispatch需要多态性,但反之则不然。可以想象一种语言与Java或C#非常相似,但其System.Object没有成员;在对值进行任何操作之前,必须进行类型转换。在这种名义语言中,会有多态,但不一定是虚方法,或任何其他动态调度机制。
动态调度是一个相关但又截然不同的概念,在大多数其他答案中都有很好的描述。但是,它在面向对象语言中的正常工作方式(选择基于第一个('this'或'Self')参数类型的函数)并不是唯一可行的方法。 Multiple dispatch也是可能的,其中选择应用于所有参数的类型。
同样,重载决策和多次发送是彼此完全相似的;重载分辨率是应用于静态类型的多分派,而多分派是应用于存储在多态位置的运行时类型的重载分辨率。
答案 15 :(得分:1)
多态性是通过依赖普通“父母”的知识来抽象地处理事物(想想像动物作为狗和猫的父母那样的heirarchies)。
例如,所有动物都可以呼吸氧气,虽然他们每个人都可以这样做,但你可以设计一个为动物提供氧气的设施,同时支持狗和猫。
稍微多一点,即使Animal是一个“抽象”标识符(没有真正的“动物”东西,只是动物类型),你也可以这样做。
答案 16 :(得分:1)
描述它的最简单方法:可以应用于多种对象的动词。
正如希勒尔所说,其他一切只是评论。
答案 17 :(得分:0)
对象必须以不同方式响应同一消息的能力。
例如,在诸如smalltalk,Ruby,Objective-C等语言中,您只需发送消息即可响应。
dao = XmlDao.createNewInstance() #obj 1
dao.save( data )
dao = RdbDao.createNewnewInstance() #obj 2
dao.save( data )
在此示例中,两个不同的对象以不同的方式响应相同的消息:“createNewInstance()and save(obj)”
他们以不同的方式对同一个信息采取行动。在上述语言中,类甚至可能不在同一个类层次结构中,只要它们响应消息即可。
在Java,C ++,C#等语言中。为了将对象分配给对象引用,它们必须通过实现接口或作为公共类的子类共享相同的类型层次结构。
简单而简单。
多态性是目前为止面向对象编程最重要和最相关的特性。
答案 18 :(得分:0)
这是一种处理不同事物的方法,这些事物可以以同样的方式做类似的事情,而无需关心他们如何做到这一点。
假设您有一系列不同类型的车辆驾驶游戏,如汽车,卡车,滑板,飞机等......它们都可以停止,但每辆车都以不同的方式停止。有些车辆可能需要换挡,有些车辆可能会停下来。 Polymophism允许你这样做
foreach (Vehicle v in Game.Vehicles)
{
v.Stop();
}
实施停止的方式推迟到不同的车辆,因此您的程序不必关心它。
答案 19 :(得分:0)
这只是一种让老年人致电新代码的方法。您编写了一些应用程序,它接受一些“Shape”接口和其他人必须实现的方法(例如 - getArea)。如果有人想出一种新的实现该接口的方式,那么旧代码可以通过getArea方法调用该新代码。
答案 20 :(得分:0)
术语多态性也可以应用于重载函数。例如,
string MyFunc(ClassA anA);
string MyFunc(ClassB aB);
是一个非面向对象的多态性示例。
答案 21 :(得分:0)
某种类型的物体(例如汽车)能够像其他类型(例如车辆)那样行动(例如制动)的能力,其通常表明共同的祖先(例如汽车是车辆的子类型)类型层次结构。
答案 22 :(得分:0)
我尝试和思考它的方式看起来相同,但根据实例可以有不同的功能。所以你可以有一个类型
interface IJobLoader
但取决于它的使用方式可以具有不同的功能,同时仍然看起来相同。你可能有BatchJobLoader,NightlyJobLoader等实例
也许我离开了。
答案 23 :(得分:-3)
多态性是面向对象的解决方案,用于将函数传递给另一个函数的问题。在C中你可以做到
void h() { float x=3.0; printf("%f", x); }
void k() { int y=5; printf("%i", y); }
void g(void (*f)()) { f(); }
g(h); // output 3.0
g(k); // output 5
在C中,如果函数依赖于其他参数,则事情变得复杂。如果函数h和k取决于不同类型的参数,则表示您遇到麻烦,必须使用铸造。您必须将这些参数存储在数据结构中,并将指向该数据结构的指针传递给g,并将其传递给h或k。 h和k将指针转换为指向正确结构的指针并解压缩数据。由于可能的铸造错误,非常混乱且非常不安全:
void h(void *a) { float* x=(float*)a; printf("%f",*x); }
void k(void *a) { int* y=(int*)a; printf("%i",*y); }
void g(void (*f)(void *a),void *a) { f(a); }
float x=3.0;
int y=5;
g(h,&x); // output x
g(k,&y); // output y
所以他们发明了多态性。 h和k被提升为类和实际函数到方法,参数是各个类的成员变量,h或k。您可以传递包含所需函数的类的实例,而不是传递函数。该实例包含自己的参数。
class Base { virtual public void call()=0; }
class H : public Base { float x; public void call() { printf("%f",x);} } h;
class K : public Base { int y; public void call() { printf("%i",y);} } k;
void g(Base &f) { f.call(); };
h.x=3.0;
k.y=5;
g(h); // output h.x
g(k); // output k.x