polymorphism c
例を挙げたC ++におけるポリモーフィズムの役割。
ポリモーフィズムは、オブジェクト指向プログラミングの4つの柱の1つです。ポリモーフィズムとは、多くの形態を持つことを意味します。それは、オブジェクトが状況に応じて多くの形をとることができる技術として定義することができます。
プログラミング用語では、オブジェクトはさまざまな条件でさまざまに動作する可能性があると言えます。
このチュートリアルでは、ポリモーフィズムのタイプ、ポリモーフィズムを実装する方法、およびポリモーフィズムの他のさまざまな概念について詳しく学習します。
swfファイルの使用方法
=> ここでC ++トレーニングチュートリアルのA〜Zを確認するには、ここをクリックしてください。
例えば、 女性はさまざまな状況で多くの役割を果たすことができます。子供にとって、彼女は母親、家の主婦、オフィスの労働者などです。したがって、女性はさまざまな役割を担い、さまざまな条件でさまざまな行動を示します。これは、ポリモーフィズムの実際の例です。
同様に、プログラミングの世界でも、オペランドが変更されたときに異なる動作をする2進加算演算子である演算子「+」を使用できます。 例えば、 両方のオペランドが数値の場合、加算を実行します。
一方、オペランドが文字列の場合は、連結演算子として機能します。したがって、ポリモーフィズムとは、一言で言えば、さまざまな形をとる、またはさまざまな条件下でさまざまに動作するエンティティを意味します。
学習内容:
ポリモーフィズムの種類
ポリモーフィズムは2つのタイプに分けられます。
- コンパイル時のポリモーフィズム
- ランタイムポリモーフィズム
これを表す図を以下に示します。
上の図に示すように、ポリモーフィズムはコンパイル時ポリモーフィズムとランタイムポリモーフィズムに分けられます。コンパイル時のポリモーフィズムは、演算子のオーバーロードと関数のオーバーロードにさらに分けられます。ランタイムポリモーフィズムは、仮想関数を使用してさらに実装されます。
コンパイル時のポリモーフィズムは、初期バインディングまたは静的ポリモーフィズムとしても知られています。このタイプのポリモーフィズムでは、オブジェクトのメソッドはコンパイル時に呼び出されます。ランタイムポリモーフィズムの場合、オブジェクトのメソッドは実行時に呼び出されます。
ランタイムポリモーフィズムは、動的または遅延バインディングまたは動的ポリモーフィズムとも呼ばれます。次のトピックでは、これらの各手法の詳細な実装について説明します。
コンパイル時のポリモーフィズムとランタイムポリモーフィズム
以下に、コンパイル時と実行時のポリモーフィズムの主な違いを見てみましょう。
コンパイル時のポリモーフィズム | ランタイムポリモーフィズム |
---|---|
静的多型または初期バインディングとも呼ばれます | 動的ポリモーフィズムまたは遅延/動的バインディングとも呼ばれます |
オブジェクトメソッドはコンパイル時に呼び出されます | オブジェクトのメソッドは実行時に呼び出されます |
通常、演算子のオーバーロードと関数のオーバーロードを使用して実装されます | 仮想関数とメソッドのオーバーライドを使用して実装 |
メソッドのオーバーロードはコンパイル時のポリモーフィズムであり、複数のメソッドが同じ名前で、異なるパラメーターリストとタイプを持つことができます。 | メソッドのオーバーライドは、複数のメソッドが同じプロトタイプで同じ名前を持つランタイムポリモーフィズムです。 |
メソッドはコンパイル時に既知であるため、実行が高速になります | メソッドは実行時に既知であるため、実行は遅くなります |
コンパイル時にすべてを知る必要があるため、ソリューションを実装するための柔軟性が低くなります | メソッドは実行時に決定されるため、複雑なソリューションを実装するための柔軟性がはるかに高くなります |
コンパイル時のポリモーフィズム
コンパイル時ポリモーフィズムは、オブジェクトのメソッドがコンパイル時に呼び出される手法です。
このタイプのポリモーフィズムは、2つの方法で実装されます。
- 関数のオーバーロード
- 演算子のオーバーロード
それぞれの手法について詳しく説明します。
関数のオーバーロード
同じ名前で、パラメーターの種類や引数の数が異なる関数が複数ある場合、関数はオーバーロードされていると言われます。
したがって、関数は、パラメータータイプ、パラメーターの順序、およびパラメーターの数に基づいてオーバーロードできます。
同じ名前で同じパラメータリストを持ち、戻り値の型が異なる2つの関数はオーバーロードされた関数ではなく、プログラムで使用するとコンパイルエラーが発生することに注意してください。
同様に、関数パラメーターがポインターのみで異なり、配列型が同等である場合は、オーバーロードに使用しないでください。
静的および非静的、constおよびvolatileなどの他のタイプ。または、デフォルト値の有無が異なるパラメーター宣言も、実装の観点からは同等であるため、オーバーロードには使用しないでください。
例えば、次の関数プロトタイプはオーバーロードされた関数です。
Add(int,int); Add(int,float); Add(float,int); Add(int,int,int);
上記のプロトタイプでは、パラメーターのタイプ、パラメーターの順序または順序、パラメーターの数などに基づいて、関数Addをオーバーロードしていることがわかります。
関数のオーバーロードをよりよく理解するために、完全なプログラミング例を見てみましょう。
#include #include using namespace std; class Summation { public: int Add(int num1,int num2) { return num1+num2; } int Add(int num1,int num2, int num3) { return num1+num2+num3; } string Add(string s1,string s2){ return s1+s2; } }; int main(void) { Summation obj; cout< 出力:
35
191
19
こんにちは世界
上記のプログラムには、2つの整数引数、3つの整数引数、および2つの文字列引数を受け取るAddという名前の3つのオーバーロードされた関数を定義するSummationクラスがあります。
main関数では、さまざまなパラメーターを提供する4つの関数呼び出しを行います。最初の2つの関数呼び出しは簡単です。 Addの3番目の関数呼び出しでは、2つの浮動小数点値を引数として提供します。
この場合、一致する関数は内部的にint Add(int、int)であり、floatはdoubleに変換されてから、intパラメーターを持つ関数と一致します。 floatの代わりにdoubleを指定した場合、パラメーターとしてdoubleを使用する別のオーバーロードされた関数があります。
c ++インタビューの質問と回答pdf
最後の関数呼び出しでは、文字列値をパラメータとして使用します。この場合、Add(+)演算子は連結演算子として機能し、2つの文字列値を連結して1つの文字列を生成します。
関数のオーバーロードの利点
関数のオーバーロードの主な利点は、コードの再利用性を促進することです。引数の型、引数の順序、および引数の数に基づいてオーバーロードされている限り、同じ名前でできるだけ多くの関数を使用できます。
これを行うことにより、同じ名前の異なる関数を使用して、異なる条件での同じ操作の動作を表すことが容易になります。
関数のオーバーロードが存在しなかった場合、異なる名前で非常に多くの異なる種類の関数を記述しなければならなかったため、コードが読み取れなくなり、適応が困難になりました。
演算子のオーバーロード
演算子のオーバーロードは、C ++の既存の演算子に異なる意味を与えるために使用する手法です。つまり、演算子をオーバーロードして、オブジェクトとしてのユーザー定義データ型に特別な意味を与えます。
C ++の演算子のほとんどは、ユーザー定義のデータ型で機能できるように、オーバーロードされているか、特別な意味が与えられています。オーバーロード中は、演算子の基本的な操作は変更されないことに注意してください。オーバーロードは、基本的なセマンティクスを同じに保つことにより、オペレーターに追加の意味を与えるだけです。
ほとんどの演算子はC ++でオーバーロードできますが、オーバーロードできない演算子もあります。
これらの演算子は、次の表にリストされています。
演算子 スコープ解決演算子(::) のサイズ メンバーセレクター(。) メンバーポインタセレクタ(*) 三項演算子(?:)
演算子をオーバーロードするために使用する関数は、「 演算子関数 」。
演算子関数は通常の関数と似ていますが、違いがあります。違いは、演算子関数の名前がキーワード「」で始まることです。 オペレーター 」の後に、オーバーロードされる演算子記号が続きます。
その後、対応する演算子がプログラムで使用されると、演算子関数が呼び出されます。これらの演算子関数は、メンバー関数またはグローバルメソッド、さらにはフレンド関数にすることができます。
演算子関数の一般的な構文は次のとおりです。
return_type classname::operator op(parameter list) { //function body }
ここで、「演算子op」は、演算子がキーワードで、opがオーバーロードされる演算子である演算子関数です。 Return_typeは、返される値の型です。
演算子関数を使用した演算子のオーバーロードを示すために、いくつかのプログラミング例を見てみましょう。
例1:メンバー演算子関数を使用した単項演算子のオーバーロード。
#include using namespace std; class Distance { public: int feet; // Constructor to initialize the object's value Distance(int feet) { this->feet = feet; } //operator function to overload ++ operator to perform increment on Distance obj void operator++() { feet++; } void print(){ cout << '
Incremented Feet value: ' << feet; } }; int main() { Distance d1(9); // Use (++) unary operator ++d1; d1.print(); return 0; }
出力:
増分フィート値:10
ここでは、演算子++関数を使用して単項インクリメント演算子をオーバーロードしました。 main関数では、この++演算子を使用して、Distanceクラスのオブジェクトをインクリメントします。
例2:メンバー演算子関数を使用した二項演算子のオーバーロード。
#include using namespace std; class Complex { int real, imag; public: Complex(int r = 0, int i =0) {real = r; imag = i;} //Operator function to overload binary + to add two complex numbers Complex operator + (Complex const &obj) { Complex c3; c3.real = real + obj.real; c3.imag = imag + obj.imag; return c3; } void print() { cout << real << ' + i' << imag << endl; } }; int main() { Complex c1(2, 5), c2(3, 7); cout<<'c1 = '; c1.print(); cout<<'c2 = '; c2.print(); cout<<'c3 = c1+c2 = '; Complex c3 = c1 + c2; // calls overloaded + operator c3.print(); }
出力:
c1 = 2 + i5
c2 = 3 + i7
c3 = c1 + c2 = 5 + i12
ここでは、演算子のオーバーロードを使用して2つの複素数を加算するという古典的な例を使用しました。複素数を表すクラスと、複素数の実数部と虚数部を追加する+演算子をオーバーロードする演算子関数を定義します。
main関数では、2つの複雑なオブジェクトを宣言し、オーバーロードされた+演算子を使用してそれらを追加して、目的の結果を取得します。
以下の例では、friend関数を使用して、2つの複素数を追加し、実装の違いを確認します。
#include using namespace std; class Complex { int real, imag; public: Complex(int r = 0, int i =0) {real = r; imag = i;} //friend function to overload binary + to add two complex numbers friend Complex operator +(Complex const &, Complex const &); void print() { cout << real << ' + i' << imag << endl; } }; Complex operator + (Complex const &c1, Complex const &c2) { Complex c3; c3.real = c1.real + c2.real; c3.imag = c1.imag + c2.imag; return c3; } int main() { Complex c1(2, 5), c2(3, 7); cout<<'c1 = '; c1.print(); cout<<'c2 = '; c2.print(); cout<<'c3 = c1+c2 = '; Complex c3 = c1 + c2; // calls overloaded + operator c3.print(); }
出力:
c1 = 2 + i5
c2 = 3 + i7
c3 = c1 + c2 = 5 + i12
プログラムの出力は同じであることがわかります。実装の唯一の違いは、前の実装のメンバー関数の代わりに、フレンド関数を使用して+演算子をオーバーロードすることです。
二項演算子にフレンド関数を使用する場合は、関数の両方のオペランドを明示的に指定する必要があります。同様に、単項演算子がフレンド関数を使用してオーバーロードされる場合、関数に単一のオペランドを提供する必要があります。
どのオペレーティングシステムを使用すればよいですか
演算子関数とは別に、次のように書くこともできます。 変換演算子 これは、あるタイプから別のタイプに変換するために使用されます。これらのオーバーロードされた変換演算子は、クラスのメンバー関数である必要があります。
例3:変換演算子を使用した演算子のオーバーロード。
#include using namespace std; class DecFraction { int numerator, denom; public: DecFraction(int num, int denm) { numerator = num; denom = denm; } // conversion operator: converts fraction to float value and returns it operator float() const { return float(numerator) / float(denom); } }; int main() { DecFraction df(3, 5); //object of class float res_val = df; //calls conversion operator cout << 'The resultant value of given fraction (3,5)= '< 出力:
与えられた分数の結果の値(3,5)= 0.6
このプログラムでは、変換演算子を使用して、指定された小数部を浮動小数点値に変換しました。変換が完了すると、変換演算子は結果の値を呼び出し元に返します。
main関数で、dfオブジェクトをres_val変数に割り当てると、変換が行われ、結果がres_valに格納されます。
単一の引数でコンストラクターを呼び出すこともできます。単一の引数を使用してクラスからコンストラクターを呼び出すことができる場合、これは「 変換 ビルダー 」。変換コンストラクターは、構築中のクラスへの暗黙的な変換に使用できます。
#include using namespace std; class Point { private: int x,y; public: Point(int i=0,int j=0) {x = i;y=j;} void print() { cout<<' x = '< 出力:
通常のコンストラクターを使用して構築されたポイント
x = 20 y = 30
変換コンストラクターを使用して構築されたポイント
x = 10 y = 0

ここに、デフォルト値でコンストラクターを定義するクラスPointがあります。 main関数では、x座標とy座標を使用してオブジェクトptを作成します。次に、ptに値10を割り当てます。ここで、変換コンストラクターが呼び出され、xに値10が割り当てられ、yにはデフォルト値0が割り当てられます。
演算子のオーバーロードルール
演算子のオーバーロードを実行するときは、以下のルールに注意する必要があります。
- C ++では、既存の演算子のみをオーバーロードできます。新しく追加された演算子はオーバーロードできません。
- 演算子がオーバーロードされている場合、オペランドの少なくとも1つがユーザー定義型であることを確認する必要があります。
- 特定の演算子をオーバーロードするために、フレンド関数を利用することもできます。
- メンバー関数を使用して単項演算子をオーバーロードする場合、明示的な引数は取りません。単項演算子がフレンド関数を使用してオーバーロードされる場合、1つの明示的な引数を取ります。
- 同様に、二項演算子がメンバー関数を使用してオーバーロードされる場合、関数に1つの明示的な引数を指定する必要があります。二項演算子がフレンド関数を使用してオーバーロードされると、関数は2つの引数を取ります。
- C ++には、すでにオーバーロードされている2つの演算子があります。これらは「=」と「&」です。したがって、同じクラスのオブジェクトをコピーするために、=演算子をオーバーロードする必要はなく、直接使用できます。
演算子のオーバーロードの利点
C ++での演算子のオーバーロードにより、演算子の機能を、組み込み型に加えてクラスオブジェクトを含むユーザー定義型に拡張できます。
演算子の機能をユーザー定義型に拡張することで、ユーザー定義型に対してさまざまな操作を実行するための複雑なコードを記述する必要はありませんが、組み込み型と同じように1回の操作で実行できます。
結論
コンパイル時ポリモーフィズムは、主に関数のオーバーロードと演算子のオーバーロードに関してコードの機能を拡張するためのオーバーロード機能を提供します。
関数のオーバーロードにより、名前は同じでパラメーターとタイプが異なる複数の関数を記述できます。これにより、コードがシンプルで読みやすくなります。演算子のオーバーロードにより、演算子の機能を拡張できるため、ユーザー定義の型に対しても基本的な操作を実行できます。
今後のチュートリアルでは、C ++でのランタイムポリモーフィズムについて詳しく学習します。
=> Easy C ++トレーニングシリーズをお読みください。
推奨読書