C++ 例によるポリモーフィズム
⚡ スマートサマリー
ポリモーフィズム C++ 単一のメンバ関数が、呼び出し元のオブジェクトに応じて異なる動作をするなど、多様な形式をとることを可能にする。これは継承に基づいており、コンパイル時または実行時に解決される2つの形式が存在する。
ポリモーフィズムとは何か C++?
In C++ポリモーフィズムは、呼び出し元のオブジェクトに基づいてメンバ関数の動作が異なるようにするものです。ポリモーフィズムはギリシャ語で「多くの形を持つ」という意味です。これは、階層構造がある場合に発生します。 クラス 遺伝によって関連している。
たとえば、関数 makeSound() があるとします。 猫がこの関数を呼び出すと、ニャーという音が鳴ります。 牛が同じ機能を呼び出すと、「モー」という音が鳴ります。
関数は XNUMX つありますが、状況が異なれば動作も異なります。 関数にはさまざまな形式があります。 したがって、ポリモーフィズムを達成しました。
基本的な考え方が確立されたので、 C++ この行動を2つの明確なカテゴリーに分類する。
多型の種類
C++ 2 種類のポリモーフィズムをサポートします。
- コンパイル時のポリモーフィズム、および
- 実行時のポリモーフィズム。
最初のカテゴリは、プログラムが実行される前にすべての関数呼び出しを解決します。
コンパイル時のポリモーフィズム
オーバーロードされた関数は、引数の数と型を一致させることで呼び出されます。情報はコンパイル時に存在します。つまり、 C++ コンパイラはコンパイル時に適切な関数を選択します。
コンパイル時のポリモーフィズムは、関数のオーバーロードと演算子のオーバーロードによって実現されます。
関数のオーバーロード
関数のオーバーロードは、名前は似ているが引数が異なる関数が多数ある場合に発生します。 引数は、数または型が異なる場合があります。
例
#include <iostream> using namespace std; void test(int i) { cout << " The int is " << i << endl; } void test(double f) { cout << " The float is " << f << endl; } void test(char const *ch) { cout << " The char* is " << ch << endl; } int main() { test(5); test(5.5); test("five"); return 0; }
出力:
コードのスクリーンショットは次のとおりです。
Code 説明:
- iostream ヘッダー ファイルをコードに含めます。 その機能を利用できるようになります。
- コードに std 名前空間を含めます。 呼び出さなくてもそのクラスを使用できるようになります。
- 整数パラメーター i を取る test という名前の関数を作成します。 { は関数テスト本体の始まりを示します。
- 上記の関数テストが呼び出された場合に実行されるステートメント。
- 上記の機能テストの本体は終了です。
- float パラメータ f を取る test という名前の関数を作成します。 { は関数テスト本体の始まりを示します。
- 上記の関数テストが呼び出された場合に実行されるステートメント。
- 上記の機能テストの本体は終了です。
- 文字パラメータ ch を受け取る test という名前の関数を作成します。 { は関数テスト本体の始まりを示します。
- 上記の関数テストが呼び出された場合に実行されるステートメント。
- 上記の機能テストの本体は終了です。
- main() 関数を呼び出します。 { は関数本体の始まりを示します。
- 関数 test を呼び出し、引数の値として 5 を渡します。 これにより、整数の引数を受け入れるテスト関数、つまり最初のテスト関数が呼び出されます。
- 関数 test を呼び出し、引数の値として 5.5 を渡します。 これにより、float 引数を受け入れるテスト関数、つまり XNUMX 番目のテスト関数が呼び出されます。
- 関数 test を呼び出し、引数の値として XNUMX を渡します。 これにより、文字引数を受け入れるテスト関数、つまり XNUMX 番目のテスト関数が呼び出されます。
- プログラムが正常に実行された場合、プログラムは値を返す必要があります。
- main() 関数の本体の終わり。
同じ名前で引数の種類が異なる XNUMX つの関数があります。 ポリモーフィズムを達成しました。
Operaトールのオーバーロード
In Operatorオーバーロードでは、 C++ オペレータまた、演算子の動作方法も変わります。例えば、+演算子を2つの文字列を連結するように定義できます。これは数値の加算演算子として知られています。定義後、+演算子を整数の間に配置した場合は加算され、文字列の間に配置した場合は連結されます。
例
#include<iostream> using namespace std; class ComplexNum { private: int real, over; public: ComplexNum(int rl = 0, int ov = 0) { real = rl; over = ov; } ComplexNum operator + (ComplexNum const &obj) { ComplexNum result; result.real = real + obj.real; result.over = over + obj.over; return result; } void print() { cout << real << " + i" << over << endl; } }; int main() { ComplexNum c1(10, 2), c2(3, 7); ComplexNum c3 = c1+c2; c3.print(); }
出力:
コードのスクリーンショットは次のとおりです。
Code 説明:
- その機能を使用するには、iostream ヘッダー ファイルをプログラムにインクルードします。
- std 名前空間を呼び出さずにそのクラスを使用するには、プログラムに std 名前空間を組み込みます。
- ComplexNum という名前のクラスを作成します。{ はクラス本体の始まりを示します。
- private アクセス修飾子を使用して、変数をプライベートとしてマークします。これは、変数がクラス内からのみアクセスできることを意味します。
- 実数とそれ以上の XNUMX つの整数変数を定義します。
- public アクセス修飾子を使用してコンストラクタを public としてマークすると、クラスの外部からもアクセスできるようになります。
- クラス コンストラクターを作成し、変数を初期化します。
- 変数 real の値を初期化します。
- 変数の値を初期化します。
- コンストラクター本体の終わり。
- + 演算子の意味をオーバーライドする必要があります。
- ComplexNum 型のデータ型結果を作成します。
- 複素数には + 演算子を使用します。この行は、ある数値の実部を別の数値の実部に追加します。
- 複素数には + 演算子を使用します。この行は、ある数値の虚数部を別の数値の虚数部に追加します。
- プログラムは、実行が成功すると変数 result の値を返します。
- + 演算子の新しい意味、つまりオーバーロードの定義はこれで終わりです。
- print() メソッドを呼び出します。
- 加算後の新しい複素数をコンソールに出力します。
- print()関数の本体の終わり。
- ComplexNum クラスの本体の終わり。
- main() 関数を呼び出します。
- 加算する実数部と複素数部の両方の値を渡します。c1 の最初の部分は c2 の最初の部分、つまり 10+3 に加算されます。c1 の 2 番目の部分は c の 7 番目の部分、つまり XNUMX+XNUMX に加算されます。
- オーバーロードされた + 演算子を使用して演算を実行し、結果を変数 c3 に格納します。
- 変数 c3 の値をコンソールに出力します。
- main() 関数の本体の終わり。
コンパイル時の多態性が早期に決定を下すのに対し、2番目のカテゴリでは実行時まで選択を延期する。
ランタイムポリモーフィズム
これは、オブジェクトのメソッドがコンパイル時ではなく実行時に呼び出されるときに発生します。 実行時のポリモーフィズムは、関数のオーバーライドによって実現されます。 呼び出される関数は実行時に確立されます。
関数のオーバーライド
関数のオーバーライドは、基本クラスの関数に派生クラスで新しい定義が与えられるときに発生します。 この時点で、基本関数はオーバーライドされたと言えます。
具体的な例を挙げますと、以下の通りです。
#include <iostream> using namespace std; class Mammal { public: void eat() { cout << "Mammals eat..."; } }; class Cow: public Mammal { public: void eat() { cout << "Cows eat grass..."; } }; int main(void) { Cow c = Cow(); c.eat(); return 0; }
出力:
コードのスクリーンショットは次のとおりです。
Code 説明:
- その機能を使用するには、iostream ヘッダー ファイルをプログラムにインポートします。
- std 名前空間を呼び出さずにそのクラスを使用するには、プログラムに std 名前空間を組み込みます。
- Mammal という名前のクラスを作成します。 { はクラス本体の始まりを示します。
- public アクセス修飾子を使用して、これから作成する関数をパブリックにアクセスできるように設定します。 このクラスの外部からアクセスできるようになります。
- Eat という名前のパブリック関数を作成します。 { は関数本体の始まりを示します。
- 関数 Eat() が呼び出されたときに cout 関数に追加されたステートメントを出力します。
- 関数eat()の本体の終わり。
- 哺乳類クラスの体の端。
- Mammal クラスを継承する Cow という名前のクラスを作成します。 Cow は派生クラスであり、Mammal は基本クラスです。 { はこのクラスの始まりを示します。
- public アクセス修飾子を使用して、これから作成する関数をパブリックにアクセスできるものとしてマークします。 このクラスの外部からアクセスできるようになります。
- 基本クラスで定義された関数 Eat() をオーバーライドします。 { は関数本体の始まりを示します。
- この関数が呼び出されたときにコンソールに出力されるステートメント。
- 関数 Eat() の本体の終わり。
- クラス Cow の本体の終わり。
- main() 関数を呼び出します。 { は、この関数の本体の始まりを示します。
- c. Cow クラスのインスタンスを作成し、名前を付けます。
- Cow クラスで定義された Eat() 関数を呼び出します。
- プログラムは正常に完了すると値を返す必要があります。
- main() 関数の終わり。
C++ 仮想機能
仮想関数は、実行時ポリモーフィズムを実装するもう一つの方法です。 C++これは、基本クラスで定義され、派生クラスで再定義される特別な関数です。仮想関数を宣言するには、virtual キーワードを使用する必要があります。キーワードは、基本クラスで関数の宣言の前に配置する必要があります。
仮想関数クラスが継承されると、仮想クラスはそのニーズに合わせて仮想関数を再定義します。 例えば:
#include <iostream> using namespace std; class ClassA { public: virtual void show() { cout << "The show() function in base class invoked..." << endl; } }; class ClassB :public ClassA { public: void show() { cout << "The show() function in derived class invoked..."; } }; int main() { ClassA* a; ClassB b; a = &b; a->show(); }
出力:
コードのスクリーンショットは次のとおりです。
Code 説明:
- iostream ヘッダー ファイルをコードに含めて、その機能を使用します。
- std 名前空間をコードに含めると、そのクラスを呼び出さずに使用できます。
- ClassA という名前のクラスを作成します。
- public アクセス修飾子を使用して、クラス メンバーをパブリックにアクセスできるものとしてマークします。
- show() という名前の仮想関数を作成します。 公的な行事となります。
- show()が呼び出されたときに印刷されるテキスト。endlは C++ 行の終了を意味するキーワード。マウス カーソルを次の行に移動します。
- 仮想関数 show() の本体の終わり。
- クラス ClassA の本体の終わり。
- クラス ClassA を継承する ClassB という名前の新しいクラスを作成します。 ClassA は基本クラスになり、ClassB は派生クラスになります。
- public アクセス修飾子を使用して、クラス メンバーをパブリックにアクセスできるものとしてマークします。
- 基本クラスで派生した仮想関数 show() を再定義します。
- 派生クラスで定義された show() 関数が呼び出されたときにコンソールに出力されるテキスト。
- show() 関数の本体の終わり。
- 派生クラス ClassB の本体の終わり。
- main() 関数を呼び出します。 プログラム ロジックは本体内に追加する必要があります。
- a という名前のポインター変数を作成します。 これは、ClassA という名前のクラスを指します。
- ClassB という名前のクラスのインスタンスを作成します。 インスタンスには b という名前が付けられます。
- アドレスbに格納されている値を変数aに代入します。
- 派生クラスで定義された show() 関数を呼び出します。 遅延バインディングが実装されました。
- main() 関数の本体の終わり。
両方のメカニズムを網羅した上で、以下の表ではそれらを並べて比較しています。
コンパイル時のポリモーフィズムと実行時のポリモーフィズム
XNUMX つの主な違いは次のとおりです。
| コンパイル時のポリモーフィズム | 実行時のポリモーフィズム |
|---|---|
| これは早期結合または静的多型とも呼ばれます。 | これは遅延/動的バインディングまたは動的多型とも呼ばれます。 |
| メソッドはコンパイル時に呼び出されます。 | メソッドは実行時に呼び出されます。 |
| 関数オーバーロードと演算子オーバーロードを介して実装 | メソッドのオーバーライドと仮想関数を介して実装されます。 |
| 例: メソッドのオーバーロード。 多くのメソッドは似たような名前を持っていますが、引数の数やタイプが異なります。 | 例: メソッドのオーバーライド。 多くのメソッドは、同様の名前と同じプロトタイプを持つ場合があります。 |
| メソッド検出がコンパイル時に行われるため、実行速度が向上します。 | メソッドの検出が実行時に行われるため、実行速度が遅くなります。 |
| Less コンパイル時にすべてがわかるため、問題解決の柔軟性が提供されます。 | メソッドは実行時に検出されるため、複雑な問題を解決するための柔軟性が大幅に向上します。 |








