継承とポリモーフィズムについて調べましたが、両者の違いはまだわかりません。
私が知っていたことから、継承は例えば(基本クラスからの派生クラスの継承メソッドとメソッドのオーバーライドも実行できます)ので、ポリモーフィズムとは何ですか?継承とポリモーフィズムの両方にどういうわけか意味がありますか?
私が間違っていることを知っているので、私を訂正してください。ありがとう
継承とポリモーフィズムについて調べましたが、両者の違いはまだわかりません。
私が知っていたことから、継承は例えば(基本クラスからの派生クラスの継承メソッドとメソッドのオーバーライドも実行できます)ので、ポリモーフィズムとは何ですか?継承とポリモーフィズムの両方にどういうわけか意味がありますか?
私が間違っていることを知っているので、私を訂正してください。ありがとう
この場合、継承はありますが、ポリモーフィズムはありません。
struct SimpleBase {
int i;
int get() const { return i; }
};
struct SimpleDerived: public SimpleBase {
int get() const { return i + 7; }
};
SimpleBase のインスタンス (またはそれへの参照またはポインター) は常にそれとまったく同じであり、派生クラスはその動作を変更できません。例えば:
int foo(SimpleBase const &obj) { return obj.get(); }
SimpleBase::get
派生型のインスタンスを渡しても、常に を呼び出します。
逆に、ポリモーフィズムを使用すると、派生クラスは基底クラスのメソッドを独自のバージョンでオーバーライドできます。
struct PolyBase {
int i;
virtual int get() const { return i; }
};
struct PolyDerived {
int get() const { return i + 7; }
};
int foo(PolyBase const &obj) { return obj.get(); }
現在、foo は、渡された派生型に応じて、それがどの派生型であるかを知らなくても、異なるメソッドを呼び出します。
したがって、ポリモーフィズムを使用すると、型のファミリ全体が共通のインターフェイスを共有でき、さまざまな派生型のすべてを知らなくても、インターフェイスで動作するコードを一度記述できます。
上に示したポリモーフィズムの形式はランタイムポリモーフィズムです。実行時に各仮想関数のどの実装を呼び出すかを判断するコードを生成します。
継承をまったく必要とせず、代わりにテンプレートを使用するコンパイル型ポリモーフィズムもあります。
ソートされたコンテナー (std::map など) を書きたいとします。特定のデータ型の格納に限定したくはありませんが、2 つの要素を比較してどちらが大きいかを確認する何らかの方法が必要です。
ランタイム アプローチは、次のような抽象基本クラスを提供する場合があります。
struct LessThanComparable {
virtual bool operator< (LessThanComparable const &) const = 0;
};
そして、コンテナに入れたいすべての型を、これから派生させて実装する必要がありますoperator<
。次に、if (a < b)
コンテナー コードを記述すると、格納する型に適した関数が呼び出されます (*)。
// requires inheritance from abstract base class,
// uses virtual call to operator<
bool less_than(LessThanComparable const &a, LessThanComparable const &b) {
return a < b;
}
STL で実際に使用されるコンパイル型アプローチ (**) は、適切なoperator<
. ただし、これはコンパイル時に解決されるため、共通の基本クラスは必要ありません。
// doesn't require any inheritance, doesn't use virtual function call,
template <typename T>
bool less_than(T const &a, T const &b) { return a < b; }
(*) a と b が異なる派生型を持つ場合に呼び出される可能性があるため、実装は簡単ではないoperator<
ことにも注意してください。テンプレート バージョンでは、どちらも同じ型Tを持っていることがわかっています。a < b
(**) わかりました。デフォルトstd::less
には LessThanComparable 要件があります。または、代替の StrictWeakOrdering を提供できます。
継承は実装手法です。ポリモーフィズムは、それを使用して実装できるものの 1 つの側面です。(それだけではありません。たとえば、からの継承
std::iterator
はポリモーフィズムとは関係ありません。)
ポリモーフィズムを使用すると、継承された親クラス間でクラスを前後にモーフィングできます。以下は、Dog および Cat クラスが Animal から継承する場合に有効です。
void takes_animal(Animal &animal) { }
Dog dog;
Cat cat;
takes_animal(dog);
takes_animal(cat);
農夫の言葉で言えば、ポリモーフィズムとは、実際の実装が実際に何であるかを知らずに、「基本」クラス (場合によってはインターフェースと呼ばれる) を操作することです。継承は、ポリモーフィズムの有無にかかわらず使用できます (つまり、継承を使用するが、処理しているオブジェクトの特定のクラスが常にわかっている場合、それが他の何かから継承されたものであっても、ポリモーフィズムではありません)。しかし、ポリモーフィズムは継承なしでは使用できません (意味をなさないだけです)。