什么是多态性,它的用途是什么,如何使用它?
当前回答
多态性允许相同的例程(函数、方法)作用于不同的类型。
由于许多现有的答案将子类型与多态性混为一谈,这里有三种实现多态性的方法(包括子类型)。
参数化(泛型)多态性允许一个例程接受一个或多个类型参数,以及正常参数,并在这些类型上运行。 子类型多态性允许例程对其参数的任何子类型进行操作。 临时多态性通常使用例程重载来授予多态行为,但也可以参考其他多态性实现。
参见:
http://wiki.c2.com/?CategoryPolymorphism
https://en.wikipedia.org/wiki/Polymorphism_ (computer_science)
其他回答
多态性是程序员编写同名方法的能力,这些方法根据对象的需要,为不同类型的对象做不同的事情。例如,如果您正在开发一个名为Fraction的类和一个名为ComplexNumber的类,这两个类都可能包含一个名为display()的方法,但它们各自实现该方法的方式不同。例如,在PHP中,你可以这样实现它:
// Class definitions
class Fraction
{
public $numerator;
public $denominator;
public function __construct($n, $d)
{
// In real life, you'd do some type checking, making sure $d != 0, etc.
$this->numerator = $n;
$this->denominator = $d;
}
public function display()
{
echo $this->numerator . '/' . $this->denominator;
}
}
class ComplexNumber
{
public $real;
public $imaginary;
public function __construct($a, $b)
{
$this->real = $a;
$this->imaginary = $b;
}
public function display()
{
echo $this->real . '+' . $this->imaginary . 'i';
}
}
// Main program
$fraction = new Fraction(1, 2);
$complex = new ComplexNumber(1, 2);
echo 'This is a fraction: '
$fraction->display();
echo "\n";
echo 'This is a complex number: '
$complex->display();
echo "\n";
输出:
This is a fraction: 1/2
This is a complex number: 1 + 2i
其他一些答案似乎暗示多态性只与继承一起使用;例如,可能Fraction和ComplexNumber都实现了一个名为Number的抽象类,该类有一个方法display(), Fraction和ComplexNumber都必须实现这个方法。但是您不需要继承来利用多态性。
至少在动态类型语言如PHP(我不知道c++或Java)中,多态性允许开发人员调用方法,而不必事先知道对象的类型,并相信将调用方法的正确实现。例如,假设用户选择创建的数字类型:
$userNumberChoice = $_GET['userNumberChoice'];
switch ($userNumberChoice) {
case 'fraction':
$userNumber = new Fraction(1, 2);
break;
case 'complex':
$userNumber = new ComplexNumber(1, 2);
break;
}
echo "The user's number is: ";
$userNumber->display();
echo "\n";
在这种情况下,将调用适当的display()方法,尽管开发人员无法提前知道用户将选择分数还是复数。
让我们打个比方。对于一个特定的音乐剧本,每个演奏它的音乐家都有自己的诠释。
音乐家可以用接口抽象,音乐家所属的流派可以是一个抽象类,它定义了一些全局解释规则,每个演奏的音乐家都可以用具体类建模。
如果你是音乐作品的听众,你可以参考剧本,例如巴赫的“富加与托卡塔”,每个演奏它的音乐家都以自己的方式多态地演奏。
这只是一个可能的设计示例(在Java中):
public interface Musician {
public void play(Work work);
}
public interface Work {
public String getScript();
}
public class FugaAndToccata implements Work {
public String getScript() {
return Bach.getFugaAndToccataScript();
}
}
public class AnnHalloway implements Musician {
public void play(Work work) {
// plays in her own style, strict, disciplined
String script = work.getScript()
}
}
public class VictorBorga implements Musician {
public void play(Work work) {
// goofing while playing with superb style
String script = work.getScript()
}
}
public class Listener {
public void main(String[] args) {
Musician musician;
if (args!=null && args.length > 0 && args[0].equals("C")) {
musician = new AnnHalloway();
} else {
musician = new TerryGilliam();
}
musician.play(new FugaAndToccata());
}
在面向对象语言中,多态性允许通过同一个接口处理和处理不同的数据类型。例如,考虑c++中的继承: 类B派生自类A。类型为A*的指针(指向类A的指针)可以用来处理类A的对象和类B的对象。
我为另一个问题提供了多态性的高级概述:
c++中的多态性
希望能有所帮助。一个提取…
...从简单的测试和[多态性]定义开始会有所帮助。考虑下面的代码:
Type1 x;
Type2 y;
f(x);
f(y);
这里,f()是执行一些操作,并被赋予值x和y作为输入。要具有多态性,f()必须能够操作至少两种不同类型的值(例如int和double),查找并执行适合类型的代码。
(继续在Polymorphism in c++)
如果你想想这个词的希腊词根,它就会变得很明显。
Poly = many: polygon = many-sided, polystyrene = many苯乙烯(a), polyglot =多种语言,等等。 Morph =变化或形式:形态学=对生物形态的研究,Morpheus =希腊梦之神,可以变成任何形式。
因此,多态性是(在编程中)为不同的底层形式(数据类型)提供相同接口的能力。
例如,在许多语言中,整数和浮点数都是隐式多态的,因为你可以加、减、乘等等,而不管它们的类型是否不同。在通常的术语中,它们很少被视为对象。
但是,以同样的方式,像BigDecimal、Rational或Imaginary这样的类也可以提供这些操作,尽管它们操作的数据类型不同。
典型的例子是Shape类和所有可以从它继承的类(正方形、圆形、十二面体、不规则多边形、splat等等)。
对于多态性,每个类都有不同的底层数据。一个点形状只需要两个坐标(当然假设它是在二维空间中)。圆需要圆心和半径。一个正方形或矩形的左上角和右下角需要两个坐标,(可能)还需要一个旋转。一个不规则的多边形需要一系列的线。
通过使类对其代码和数据负责,您可以实现多态性。在这个例子中,每个类都有自己的Draw()函数,客户端代码可以简单地这样做:
shape.Draw()
为了得到任何形状的正确行为。
这与旧的处理方法相反,旧的方法中代码与数据是分开的,并且您将拥有像drawSquare()和drawCircle()这样的函数。
面向对象、多态和继承都是密切相关的概念,了解它们至关重要。在我漫长的职业生涯中,有许多“银弹”基本上都失败了,但OO范例已经被证明是一个很好的范例。学习它,理解它,爱上它——你会为你所做的感到高兴:)
(a)我最初写这个是作为一个笑话,但它被证明是正确的,因此,并不那么有趣。单体苯乙烯是由碳和氢组成的,C8H8,聚苯乙烯是由(C8H8)n组成的。
也许我应该说明,息肉是字母p的多次出现,尽管现在我必须解释这个笑话,即使这似乎也不好笑。
有时候,你应该在落后的时候就放弃:-)
推荐文章
- 什么是依赖倒置原则?为什么它很重要?
- 为什么在Python方法中需要显式地有“self”参数?
- 如何在方法中访问“静态”类变量?
- 为什么c#不提供c++风格的'friend'关键字?
- String, StringBuffer和StringBuilder
- 存储库和服务层的区别?
- DDD -实体不能直接访问存储库的规则
- 为什么STL如此严重地基于模板而不是继承?
- 如何在Objective-C中声明类级属性?
- 面向方面编程与面向对象编程
- c++中类似于java的instanceof
- 在python中遍历对象属性
- 将类代码分离为头文件和cpp文件
- 在PHP中使用getter和setter而不是函数或简单的公共字段有什么优点?
- 基于原型的继承与基于类的继承