ポリモーフィズムについていま勉強してるのですがポリモーフィズムについての利点と欠点がよく分かりません。
あと勉強してるなかでポリモーフィズムはなんとなく継承と似てるような気がしますのですが違いはあるのでしょう。
解説
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ポリモーフィズムというのは、一つの名前に複数の実体を関係づけ、そして、その名前を使うときに、使っている場所のコンテキストによって実体が自動的に選択される仕組みのことです。こういう一般的な言い方だと、何言っているのか、よくわからないので具体例を示してみます。
変数の中身を、簡単な型の説明付きで表示する関数、printMe
を作るとします。
C++
1#include <iostream> 2using namespace std; 3 4void printMe(int v) 5{ 6 cout << "int:" << v << endl; 7} 8 9void printMe(double v) 10{ 11 cout << "double:" << v << endl; 12} 13 14int main() 15{ 16 int i = 1; 17 double d = 2.5; 18 19 printMe(i); // int:1 20 printMe(d); // double:2.5 21 22 return 0; 23}
上の例では、printMe
という一つの名前に、引数が int
用の関数の実体と、double
用の実体の二つが結びついています。printMe
という機能を呼び出すとき、引数の型によって、違う関数の実体が呼び出されているのが分かると思います。
printMe
というのは、使う側からすれば、変数の中身を簡単な説明付きで表示したい、という一つの目的しかありません。しかし、実際にコーディングすると、変数の型によって、やり方を変えなければなりません。ポリモーフィズムがなければ、int
の変数にはprintMeInt
を、double
の変数にはprintMeDouble
を使うといったようなことをしなければならず、変数を表示したいだけなのに、いくつも名前を使い分けなければならず面倒です。ポリモーフィズムがあれば、一つの目的に一つの名前で済み、プログラムが作りやすく、わかりやすくなります。これがポリモーフィズムの利点です。(逆に言えば、違う目的なのに同じ名前を付けてしまうこともできるわけで、そうなると悲惨です。)
継承とポリモーフィズムの関係ですが、上の例で分かるように、ポリモーフィズムには継承が絶対に必要というわけではありません。
C++ や Java のような言語では変数にも型があり、あるクラスの変数には、そのクラスか、そのサブクラスのオブジェクトしか代入できません。したがって、オブジェクト間でポリモーフィズムを利用しようとすると、継承をつかってクラスの親子関係を定義しなければなりません。
一方、例えば Python のように変数には型がない言語では、継承なしでもポリモーフィズムが利用可能です。
投稿2016/12/04 00:46
退会済みユーザー
総合スコア0
0
こんにちは。
ポリモーフィズムはなんとなく継承と似てるような気がしますのですが
普通、ポリモーフィズムは継承して実現しますよ。
さて、派生クラスのインスタンスを基底クラス型のポインタで指し示することができるのがポリモーフィズムです。
何が嬉しいかというと、基底クラスへのポインタで様々な派生クラスのインスタンスを管理できますし、操作することさえできます。
例えば、基底クラスとしてペットクラスがあって、それを派生して犬クラスや猫クラスを作ったとします。
ペットクラスへのポインタ配列を作り犬クラスのインスタンスへのポインタや猫クラスのインスタンスへのポインタを代入できます。(普通は型が違うと代入できませんが、基底クラスへのポインタであればできます。)
更に、そのポインタ配列の要素をforループで回して、登録されているペットインスタンスに「鳴け」と指示したら、犬クラスのインスタンスは「ワンワン」と返して、猫クラスのインスタンスは「ニャーニャー」と返すことができます。
これは本当に便利ですよ。
投稿2016/12/03 12:55
総合スコア23272
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
C++
1#include <iostream> 2 3class Crier 4{ 5public: 6 virtual void cry() = 0; 7}; 8 9 10class Baby : public Crier 11{ 12public: 13 Baby() { } 14 15 void cry() 16 { 17 std::cout << "おぎゃー\n"; 18 } 19}; 20 21 22class Cat : public Crier 23{ 24public: 25 Cat() { } 26 27 void cry() 28 { 29 std::cout << "ニャーニャー\n"; 30 } 31}; 32 33 34class Horse : public Crier 35{ 36public: 37 Horse() { } 38 39 void cry() 40 { 41 std::cout << "ヒヒーン\n"; 42 } 43}; 44 45 46int main(int argc, char* argv[]) 47{ 48 Crier* criers[] = { new Baby(), new Cat(), new Horse() }; 49 50 for (int i = 0; i < sizeof(criers) / sizeof(criers[0]); i++) 51 { 52 criers[i]->cry(); 53 } 54 55 return 0; 56}
呼び出し側は criers[i]->cry(); だけなのに、それぞれの派生クラスのcry()が呼び出されます。
Catクラスのcry()の実装を、「猫の鳴き声のオーディオファイル再生」に変えても、
呼び出し側を一切変更せずに、「猫の鳴き声のオーディオファイル再生」ができます。
継承とオーバーライドのルールに従えば、未実装の関数さえ呼び出すコードが書けるのです。
投稿2016/12/04 01:44
総合スコア1105
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2016/12/04 01:03
退会済みユーザー
2016/12/04 01:11
2016/12/04 02:47
2016/12/05 02:02 編集