在MSDN中阅读about polymorphism时, 我看到了一个虚拟和重写方法的例子:
public class BaseClass
{
public virtual void DoWork() { }
public virtual int WorkProperty
{
get { return 0; }
}
}
public class DerivedClass : BaseClass
{
public override void DoWork() { }
public override int WorkProperty
{
get { return 0; }
}
}
DerivedClass B = new DerivedClass();
B.DoWork(); // Calls the new method.
BaseClass A = (BaseClass)B;
A.DoWork(); // Also calls the new method.
我想知道的是,在什么情况下应该有人这样做? 我无法以任何方式看到它是如何有用的。有人可以举一个现实世界的例子吗?
答案 0 :(得分:3)
每当您想要引用某些对象时,这很有用,并且您无法保留其确切类型的引用。例如,如果您有一个混合类型的对象列表:
List<BaseClass> list = new List<BaseClass>() {
new BaseClass(),
new DerivedClass(),
new BaseClass(),
new BaseClass(),
new DerivedClass(),
new DerivedClass()
};
现在您有一个BaseClass
引用列表,但其中一些引用了DerivedClass
个实例。
当您想要使用它们时,您不需要检查它们的类型。您可以调用虚拟DoWork
方法,并为BaseClass.DoWork
实例调用BaseClass
方法,并为DerivedClass.DoWork
调用DerivedClass
方法实例:
foreach (BaseClass b in list) {
b.DoWork();
}
答案 1 :(得分:2)
你关心的是Dancer
可以跳舞。如果您持有Dancer
的引用,那么您不应该关心该舞者如何跳舞 - 只有他们这样做。这也是接口背后的想法。
所以,你举办一个舞池派对,你想让人们跳舞。但是让他们成为自己,以他们想要的方式跳舞,并享受美好时光。
List<Dancer> danceFloor = new List<Dancer>();
danceFloor.Add(new ReservedDancer());
danceFloor.Add(new SuperFreakDancer ());
public class Dancer
{
public virtual void DoYourDance()
{
// do the robot. Everyone knows that one right?
}
}
public class ReservedDancer : Dancer
{
public override void DoYourDance()
{
// do the waltz
}
}
public class SuperFreakDancer : Dancer
{
public override void DoYourDance()
{
// breakdance !!!
}
}
至于为什么你可以在同一个函数中使用多态分配,考虑一个Dancer
工厂方法(你可以将它添加到Dancer
类,让DancerType
成为枚举描述每个舞者类型):
public static Dancer NewDancerFromType(DancerType type)
{
Dancer ret = null;
switch (type)
{
case DancerType.Reserved:
ret = new ReservedDancer();
break;
case DancerType.SuperFreak:
ret = new SuperFreakDancer();
break;
}
return ret;
}
有时候,让我们说Dancer
是public
,但其子类是private
。这样你可以使用这个工厂方法来获取那些子类的实例,但你仍然会持有Dancer
个引用。为了实际的目的,我已经多次实现了这种模式,我可以告诉你这个但是很长时间并开始摆脱这个主题的主题。
答案 2 :(得分:2)
我认为与面向对象编程和多态性相关的大多数教学/文献的问题在于,实际上有用的实际例子很少,可能是因为它们太复杂了。话虽如此,这是另一个糟糕的例子:)
基本上,任何多态代码都可以重写为if-else语句。请考虑以下代码:
class Car {
public virtual void Drive() {
Console.WriteLine("Driving like a normal car");
}
}
class RaceCar : Car {
public override void Drive() {
Console.WriteLine("Driving really fast!");
}
}
现在,在史前(OO前)的时间里,如果我们有赛车,我们会在某处提供一些代码:
if (isRaceCar) {
Console.WriteLine("Driving really fast!");
} else {
Console.WriteLine("Driving like a normal car");
}
那么,为什么我们要创建这个完整的类结构,第二段代码看起来要简单得多。
我们说我们增加了第三种车型:
class OldCar : Car {
public override void Drive() {
Console.WriteLine("Driving very slowly");
}
}
现在,我们的布尔系统将不再起作用,因此我们需要一个开关或其他东西
switch (carType) {
case RaceCar: ...
case OldCar: ...
case Car: ...
}
好吧,好吧,好吧。但是现在我们还希望我们的汽车除了驾驶之外还要做其他事情,例如GetIn
,GetOut
,Stop
,DoMaintenance
等等。现实世界的例子可以大得多。
如果没有多态性,这将导致我们的汽车相关代码遍布整个地方,如果添加新型汽车,很容易忘记某个地方的开关案例。使用多态,特别是使用抽象方法和接口,忘记其中一种情况将导致编译器错误而不是运行时错误或隐藏错误,因为我们被迫实施适当的方法。
重要的是要注意,当使用多态时,这些if / else或switch案例仍然存在,但所有的努力都是由编译器本身完成的,我们不必考虑它。
这只是一个例子,还有其他好处,例如:
Car
并将其发送到其他代码来处理与汽车有关的代码)。这意味着您在添加新型汽车时会重复使用处理汽车的代码。