次の例を考えてみましょう。
#include <iostream>
using namespace std;
class Animal
{
public:
virtual void makeSound() {cout << "rawr" << endl;}
};
class Dog : public Animal
{
public:
virtual void makeSound() {cout << "bark" << endl;}
};
int main()
{
Animal animal;
animal.makeSound();
Dog dog;
dog.makeSound();
Animal badDog = Dog();
badDog.makeSound();
Animal* goodDog = new Dog();
goodDog->makeSound();
}
出力は次のとおりです。
rawr
bark
rawr
bark
しかし、確かに出力は「生の樹皮樹皮樹皮」であるべきだと思いました。 badDogとは何ですか?
更新:あなたは興味があるかもしれません 私の別の質問 。
これは「スライス」と呼ばれる問題です。
Dog()
はDog
オブジェクトを作成します。 Dog().makeSound()
を呼び出すと、期待どおりに「樹皮」が出力されます。
問題は、タイプbadDog
のオブジェクトであるAnimal
をこのDog
で初期化していることです。 Animal
にはAnimal
のみを含めることができ、Animal
から派生したものは含まれないため、Animal
のDog
部分を取り、それで初期化します。
badDog
のタイプは常にAnimal
です。それは決して他のものになることはできません。
C++でポリモーフィックな動作を取得する唯一の方法は、ポインターを使用するか(goodDog
の例で示したように)、参照を使用することです。
参照(例:_Animal&
_)はAnimal
から派生した任意のタイプのオブジェクトを参照でき、ポインター(例:_Animal*
_)はAnimal
から派生した任意のタイプのオブジェクトを指すことができます。ただし、プレーンなAnimal
は常にAnimal
であり、他には何もありません。
JavaやC#などの一部の言語には参照セマンティクスがあり、変数は(ほとんどの場合)オブジェクトへの単なる参照であるため、_Animal rex;
_が与えられると、rex
は実際にはいくつかのAnimal
への単なる参照になります。 、およびrex = new Dog()
は、rex
が新しいDog
オブジェクトを参照するようにします。
C++はそのようには機能しません。変数はC++のオブジェクトを参照せず、変数はオブジェクトです。 C++でrex = Dog()
と言うと、新しいDog
オブジェクトがrex
にコピーされ、rex
は実際にはタイプAnimal
であるため、スライスされ、Animal
パーツのみがコピーされます。これらは値セマンティクスと呼ばれ、C++のデフォルトです。 C++で参照セマンティクスが必要な場合は、参照またはポインターを明示的に使用する必要があります(これらは、C#またはJavaでの参照と同じではありませんが、より類似しています)。
Animal badDog = Dog();
ad.makeSound();
Dog
をインスタンス化し、それを値でAnimal
変数に割り当てると、 スライス オブジェクトになります。これは基本的に、Dog
からすべてのbadDog
-nessを取り除き、それを基本クラスにすることを意味します。
基本クラスでポリモーフィズムを使用するには、ポインタまたは参照のいずれかを使用する必要があります。