C++ ポリモーフィズムと例
C++ のポリモーフィズムとは
C++ では、ポリモーフィズムにより、メンバー関数はそれを呼び出す/呼び出すオブジェクトに基づいて異なる動作をします。ポリモーフィズムは、多くの形を持つことを意味するギリシャ語です。継承によって関連するクラスの階層がある場合に発生します。
たとえば、関数 makeSound() があるとします。猫がこの関数を呼び出すと、鳴き声が鳴ります。牛が同じ機能を呼び出すと、モーーという音がします。
機能は 1 つありますが、状況によって動作が異なります。関数には多くの形式があります。したがって、ポリモーフィズムを達成しました。
この C++ チュートリアルでは、次のことを学びます:
ポリモーフィズムとは?
ポリモーフィズムの種類
コンパイル時のポリモーフィズム
関数のオーバーロード
演算子のオーバーロード
ランタイム ポリモーフィズム
関数のオーバーライド
C++ 仮想関数
コンパイル時のポリモーフィズムとランタイム ポリモーフィズム
ポリモーフィズムの種類
C++ は 2 種類のポリモーフィズムをサポートしています:
コンパイル時のポリモーフィズム、および
ランタイム ポリモーフィズム。
コンパイル時のポリモーフィズム
オーバーロードされた関数を呼び出すには、引数の数と型を一致させます。情報はコンパイル時に存在します。これは、C++ コンパイラがコンパイル時に適切な関数を選択することを意味します。
コンパイル時のポリモーフィズムは、関数のオーバーロードと演算子のオーバーロードによって実現されます。
関数のオーバーロード
関数のオーバーロードは、名前が似ているが引数が異なる関数が多数ある場合に発生します。引数は、数または型の点で異なる場合があります。
例 1:
#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;
}
出力:
コードのスクリーンショットは次のとおりです:
コードの説明:
<オール>
iostream ヘッダー ファイルをコードにインクルードします。その機能を使用できるようになります。
コードに std 名前空間を含めます。クラスを呼び出さずに使用できるようになります。
整数パラメータ i を受け取る test という名前の関数を作成します。 { は、関数テストの本体の開始を示します。
上記の関数 test が呼び出された場合に実行されるステートメント。
上記の機能テストの本文の終わり。
float パラメータ f を受け取る test という名前の関数を作成します。 { は、関数テストの本体の開始を示します。
上記の関数 test が呼び出された場合に実行されるステートメント。
上記の機能テストの本文の終わり。
文字パラメータ ch を受け取る test という名前の関数を作成します。 { は、関数テストの本体の開始を示します。
上記の関数 test が呼び出された場合に実行されるステートメント。
上記の機能テストの本文の終わり。
main() 関数を呼び出します。 { は、関数の本体の開始を示します。
関数 test を呼び出し、引数の値として 5 を渡します。これにより、整数の引数を受け入れるテスト関数、つまり最初のテスト関数が呼び出されます。
関数 test を呼び出し、引数の値として 5.5 を渡します。これにより、float 引数を受け入れるテスト関数、つまり 2 番目のテスト関数が呼び出されます。
関数 test を呼び出し、引数の値として 5 を渡します。これにより、文字引数を受け入れるテスト関数、つまり 3 番目のテスト関数が呼び出されます。
プログラムが正常に実行された場合、プログラムは値を返さなければなりません。
main() 関数の本体の終わり。
名前は同じだが引数の型が異なる 3 つの関数があります。ポリモーフィズムを達成しました。
演算子のオーバーロード
演算子のオーバーロードでは、C++ 演算子の新しい意味を定義します。また、オペレーターの働き方も変わります。たとえば、+ 演算子を定義して 2 つの文字列を連結できます。数値を加算するための加算演算子として知られています。定義の後、整数の間に配置すると、それらが追加されます。文字列の間に配置すると、それらが連結されます。
例 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();
}
出力:
コードのスクリーンショットは次のとおりです:
コードの説明:
<オール>
関数を使用するために、iostream ヘッダー ファイルをプログラムにインクルードします。
クラスを呼び出さずに使用するために、std 名前空間をプログラムに含めます。
ComplexNum という名前のクラスを作成します。 { は、クラス本体の開始を示します。
プライベート アクセス修飾子を使用して、変数をプライベートとしてマークします。つまり、変数はクラス内からのみアクセスできます。
real と over の 2 つの整数変数を定義します。
public アクセス修飾子を使用して、コンストラクターを public としてマークします。つまり、クラスの外からでもアクセスできるようになります。
クラス コンストラクターを作成し、変数を初期化します。
変数 real の値を初期化します。
変数 over の値を初期化します。
コンストラクタ本体の終わり。
+ 演算子の意味をオーバーライドする必要があります。
ComplexNum 型のデータ型結果を作成します。
複素数には + 演算子を使用します。この行は、数値の実部を別の数値の実部に加算します。
複素数には + 演算子を使用します。この行は、数値の虚部を別の数値の虚部に追加します。
実行が成功すると、プログラムは変数 result の値を返します。
+ 演算子の新しい意味、つまりオーバーロードの定義の終わり。
print() メソッドを呼び出します。
加算後の新しい複素数をコンソールに出力します。
print() 関数の本体の終わり。
ComplexNum クラスの本体の終わり。
main() 関数を呼び出します。
追加する実部と複素部の両方の値を渡します。 c1 の最初の部分は c2 の最初の部分、つまり 10+3 に加算されます。 c1 の 2 番目の部分は、c の 2 番目の部分、つまり 2+7 に加算されます。
オーバーロードされた + 演算子を使用して演算を実行し、結果を変数 c3 に格納します。
変数 c3 の値をコンソールに出力します。
main() 関数の本体の終わり。
ランタイム ポリモーフィズム
これは、オブジェクトのメソッドがコンパイル時ではなく実行時に呼び出されたときに発生します。ランタイム ポリモーフィズムは、関数のオーバーライドによって実現されます。呼び出される/呼び出される関数は、実行時に確立されます。
関数のオーバーライド
関数のオーバーライドは、基本クラスの関数に派生クラスで新しい定義が与えられたときに発生します。その時点で、基本関数はオーバーライドされたと言えます。
例:
#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;
}
出力:
コードのスクリーンショットは次のとおりです:
コードの説明:
<オール>
iostream ヘッダー ファイルをプログラムにインポートして、その関数を使用します。
クラスを呼び出さずに使用するために、std 名前空間をプログラムに含めます。
Mammal という名前のクラスを作成します。 { は、クラス本体の開始を示します。
public アクセス修飾子を使用して、作成しようとしている関数をパブリックにアクセスできるように設定します。このクラスの外からアクセスできます。
eat というパブリック関数を作成します。 { は、関数本体の開始を示します。
関数 eat() が呼び出されたときに cout 関数に追加されたステートメントを出力します。
関数eat()の本体の終わり。
Mammal クラスの体の終わり。
Mammal クラスを継承する Cow という名前のクラスを作成します。 Cow は派生クラスで、Mammal は基本クラスです。 { は、このクラスの始まりを示します。
public アクセス修飾子を使用して、作成しようとしている関数を公開アクセス可能としてマークします。このクラスの外からアクセスできます。
基本クラスで定義された関数 eat() をオーバーライドします。 { は、関数本体の開始を示します。
この関数が呼び出されたときにコンソールに出力するステートメント。
関数 eat() の本体の終わり。
Cow クラスのボディの終わり。
main() 関数を呼び出します。 { は、この関数の本体の開始を示します。
Cow クラスのインスタンスを作成し、c という名前を付けます。
Cow クラスで定義されている eat() 関数を呼び出します。
プログラムは、正常終了時に値を返さなければなりません。
main() 関数の終わり。
C++ 仮想関数
仮想関数は、C++ でランタイム ポリモーフィズムを実装するもう 1 つの方法です。これは、基本クラスで定義され、派生クラスで再定義される特別な関数です。仮想関数を宣言するには、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();
}
出力:
コードのスクリーンショットは次のとおりです:
コードの説明:
<オール>
コードに iostream ヘッダー ファイルをインクルードして、その関数を使用します。
コードに std 名前空間を含めて、呼び出さずにそのクラスを使用します。
ClassA という名前のクラスを作成します。
パブリック アクセス修飾子を使用して、クラス メンバーを公開アクセス可能としてマークします。
show() という名前の仮想関数を作成します。公務となります。
呼び出された show() が呼び出されたときに出力するテキスト。 endl は C++ のキーワードで、終了行を意味します。マウスカーソルを次の行に移動します。
仮想関数 show() の本体の終わり。
クラス ClassA の本体の終わり。
クラス ClassA を継承する ClassB という名前の新しいクラスを作成します。 ClassA は基本クラスになり、ClassB は派生クラスになります。
パブリック アクセス修飾子を使用して、クラス メンバーを公開アクセス可能としてマークします。
基本クラスで派生した仮想関数 show() を再定義します。
派生クラスで定義された show() 関数が呼び出されたときにコンソールに出力するテキスト。
show() 関数の本体の終わり。
派生クラス ClassB の本体の終わり。
main() 関数を呼び出します。プログラム ロジックは、その本体内に追加する必要があります。
a という名前のポインター変数を作成します。これは、ClassA という名前のクラスを指しています。
ClassB という名前のクラスのインスタンスを作成します。インスタンスには b という名前が付けられます。
変数 a のアドレス b に格納されている値を割り当てます。
派生クラスで定義された show() 関数を呼び出します。遅延バインディングが実装されました。
main() 関数の本体の終わり。
コンパイル時のポリモーフィズムとランタイム ポリモーフィズム
2 つの主な違いは次のとおりです。
コンパイル時のポリモーフィズム ランタイム ポリモーフィズム アーリー バインディングまたは静的ポリモーフィズムとも呼ばれますレイト/ダイナミック バインディングまたはダイナミック ポリモーフィズムとも呼ばれますメソッドはコンパイル時に呼び出されます/呼び出されますメソッドは実行時に呼び出されます関数のオーバーロードと演算子のオーバーロードを介して実装されますメソッドのオーバーライドと仮想関数を介して実装されます例、メソッドのオーバーロード.多くのメソッドは名前が似ていても、引数の数や型が異なる場合があります。例、メソッドのオーバーライド。多くのメソッドが似たような名前と同じプロトタイプを持つ場合があります。メソッドの検出がコンパイル時に行われるため、実行が高速になります。メソッドの検出が実行時に行われるため、実行が遅くなります。コンパイル時にすべてが既知であるため、問題解決の柔軟性が低くなります。柔軟性が非常に高くなります。メソッドは実行時に発見されるため、複雑な問題を解決するために提供されています。
まとめ: ポリモーフィズムとは、多くの形を持つことを意味します。
継承によって関連するクラスの階層がある場合に発生します。
ポリモーフィズムにより、関数はそれを呼び出す/呼び出すオブジェクトに基づいて異なる動作をすることができます。
コンパイル時のポリモーフィズムでは、呼び出される関数はコンパイル時に確立されます。
実行時ポリモーフィズムでは、呼び出される関数は実行時に確立されます。
コンパイル時のポリモーフィズムは、関数のオーバーロードと演算子のオーバーロードによって決定されます。
関数のオーバーロードには、名前が似ていても引数が異なる関数が多数あります。
パラメータの数またはタイプが異なる場合があります。
演算子のオーバーロードでは、C++ 演算子の新しい意味が定義されています。
ランタイム ポリモーフィズムは、関数のオーバーライドによって実現されます。
関数のオーバーライドでは、派生クラスは基本クラスで定義された関数に新しい定義を与えます。