ポリモーフィズムとは何ですか?
ポリモーフィズムは文字通り「複数の状態」を意味します。オブジェクト指向言語では、インターフェイスの複数の異なる実装をポリモーフィズムと呼びます。 Charlie Calverts のポリモーフィズムの説明を引用します。ポリモーフィズムは、親オブジェクトを 1 つ以上の子オブジェクトと等しくなるように設定できる技術で、代入後、現在の値に基づいて親オブジェクトをその子オブジェクトに割り当てることができます。 . 機能はさまざまな方法で動作します (「Insider Delphi 4 プログラミング テクノロジー」より)。簡単に言うと、それは 1 つの文です: サブクラス型のポインターを親クラス型のポインターに割り当てることが許可されています (はい、この文章は Baidu 百科事典から引用しています)。それでは、ポリモーフィズムの役割は何であり、その実際の開発価値は何でしょうか?実際のアプリケーション開発において、オブジェクト指向ポリモーフィズムを使用する主な目的は、異なるサブクラス オブジェクトを 1 つの親クラスとして扱うことができ、異なるサブクラス オブジェクト間の差異をシールドして汎用オブジェクトを記述して、一般的なプログラミングを実現できることです。変化するニーズに適応します。
以下は、PHP におけるポリモーフィズムの 2 つの実装です
メソッドのオーバーロード
オーバーロードはクラスポリモーフィズムの実装です。関数のオーバーロードとは、識別子が複数の関数名として使用され、同じ名前を持つこれらの関数が関数の番号またはパラメーターの型によって区別できるため、呼び出しに混乱が生じないことを意味します。つまり、呼び出されたとき、メソッド名は同じでも、異なるパラメータに従って対応する関数を自動的に呼び出すことができます。
PHP がメソッドのオーバーロードを直接サポートしている場合。そして、上記の例を実行すると、パラメータが渡された場合と渡されなかった場合で異なる値が返されます。ただし、PHP はオーバーロードを直接サポートしていないため、上記のように直接定義するとエラーが報告されます。どのようなエラーが報告されるのでしょうか?次のエラーが報告されます。
これは、関数 A を繰り返し定義することはできず、エラーを報告する行数は正確に次の行であることを意味します。
リーリーそのため、php はリロードを直接サポートしていません。共著者は長い間、php はサポートしていないと言い続けてきました。 。心配しないでください。私が言ったのは、これは直接サポートされていないため、php に間接的にサポートさせることができるということです。このとき、オーバーロードをサポートする関数が使用されます。それは__call()です。 __call() メソッドは 2 つのパラメータを取る必要があります。最初のパラメータには呼び出されるメソッドの名前が含まれ、2 番目のパラメータにはメソッドに渡されるパラメータの配列が含まれます。このメソッドを使用すると、関数のオーバーロードと同様の関数を実現できます。以下のコードを見てください。
メソッドを定義する場合、オブジェクトが display() メソッドに渡されると、displayObject() メソッドが呼び出され、配列が渡されると、displayArray() メソッドが呼び出されます。渡された場合、displayScalar() メソッドが呼び出されます。 。 。以下を呼び出すと、最初に配列が渡され、次に displayArray() が呼び出されることがわかります。 2 番目に渡されたものはオブジェクトでも配列でもありません。他のコンテンツに属しており、displayScalar() メソッドが呼び出されます。このように、__call() メソッドを使用して、他の言語と同様のメソッドのオーバーロードを実装します。
メソッドオーバーライド
いわゆる上書きとは、本質的には書き換えです。つまり、サブクラスが親クラスからいくつかのメソッドを継承し、そのサブクラスが同じメソッドを内部で定義している場合、新しく定義されたメソッドは親クラスから継承されたメソッドをオーバーライドし、サブクラスは内部で定義されたメソッドのみを呼び出すことができます。
には次の要件があります:
1. 親クラスとサブクラスにまったく同じパラメーターと名前を持つメソッドがある場合、サブクラスのメソッドは親クラスのメソッドをオーバーライドします。
2. メソッド カバレッジを実装する場合、アクセス修飾子は異なっていてもかまいませんが、サブクラスのアクセス スコープは親クラスのアクセス スコープ以上である必要があります。
3. パラメータと名前は同じである必要があります。サブクラスが親クラスと同じ名前である必要はありません。
これらの点について以下に説明します:
最初のポイントは、メソッド カバレッジを達成するにはパラメータが一貫している必要があります。パラメータの数が一致しない場合、エラーが報告されます (これには、上記のメソッドのオーバーロードが含まれます)。メソッド名が一致しない場合、上書きされるのはサブクラスの新しく定義されたメソッドのみです。 ;
2つ目のポイントは、これがphpなどの言語の設計ルールであるということです。私が理解しているのは、より高いレベルにあるものにアクセスする方が簡単であるということです。より低いレベルにあるものにアクセスしたい場合は、より高い権限が必要です。
コードを見てください:
リーリーこれは「女性の歌」をアウトプットする通常の方法です。しかし、女性の sing() メソッドが proccted に変更され、親要素が public() に変更された場合、つまり、親クラスのアクセス許可がサブクラスのアクセス許可よりも大きく設定された後、次のエラーが発生します。報告される。
第三点,是要求参数和名字一样,具体就是要求参数的个数与父类相同,而并不是参数名称一致。即传递的参数名字可以为任意,只要保证传递的个数相同即可。
以上内容简单介绍了PHP语言中多态的两个实现。
PS:重写、覆盖、重载、多态几个概念的区别分析
override->重写(=覆盖)、overload->重载、polymorphism -> 多态
override是重写(覆盖)了一个方法,以实现不同的功能。一般是用于子类在继承父类时,重写(重新实现)父类中的方法。
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
6、静态方法不能被重写为非静态的方法(会编译出错)。
overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。
重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
多态的概念比较复杂,有多种意义的多态,一个有趣但不严谨的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。
一般,我们使用多态是为了避免在父类里大量重载引起代码臃肿且难于维护。
举个例子:
public class Shape { public static void main(String[] args){ Triangle tri = new Triangle(); System.out.println("Triangle is a type of shape? " + tri.isShape());// 继承 Shape shape = new Triangle(); System.out.println("My shape has " + shape.getSides() + " sides."); // 多态 Rectangle Rec = new Rectangle(); Shape shape2 = Rec; System.out.println("My shape has " + shape2.getSides(Rec) + " sides."); //重载 } public boolean isShape(){ return true; } public int getSides(){ return 0 ; } public int getSides(Triangle tri){ //重载 return 3 ; } public int getSides(Rectangle rec){ //重载 return 4 ; } } class Triangle extends Shape { public int getSides() { //重写,实现多态 return 3; } } class Rectangle extends Shape { public int getSides(int i) { //重载 return i; } }
注意Triangle类的方法是重写,而Rectangle类的方法是重载。对两者比较,可以发现多态对重载的优点:
如果用重载,则在父类里要对应每一个子类都重载一个取得边数的方法;
如果用多态,则父类只提供取得边数的接口,至于取得哪个形状的边数,怎样取得,在子类里各自实现(重写)。