C++ 中的多态性

こんにちは、夢を持つプログラマーの皆さん!今日、私たちはC++の多態性の魔法の世界に興味深い旅をすることになります。この言葉が恐ろしく聞こえても心配しないでください — このレッスンの終わりまでに、あなたはこの多態性に対する安心感をお気に入りのスニーカーと同じくらい持つことができるようになるでしょう!

C++ Polymorphism

多態性とは?

コードに飛び込む前に、まず多態性が実際に何を意味するかを理解しましょう。この言葉はギリシャ語から来ており、「poly」は多く、そして「morph」は形を意味します。プログラミングでは、多態性は異なる型のオブジェクトを共通の基本型のオブジェクトとして扱うことができます。それはあるユニバーサルリモコンがさまざまなデバイスを制御できるように、とてもクールなことですよね?

実世界の比喩

動物園にいるところを想像してみてください。異なる動物 — 狮子、象、ペンギンを見ています。彼らはすべて動物ですが、異なる行動をします。餌を与える時、動物園の飼育員はそれぞれの動物が正確にどんな種類の動物であるかを知る必要はありません。彼らは一般的な「食べる」コマンドを呼び出し、それぞれの動物が自分だけのやり方で反応します。それが多態性の動作です!

仮想関数

では、C++の多態性の詳細について見ていきましょう。まずは仮想関数から始めます。

仮想関数とは?

仮想関数は、C++における特別な関数で、プログラムが実行時にオブジェクトの型に基づいてどの関数を呼び出すかを決定することができます。これは、ポインタや参照の型に基づいているのではなく、参照されているオブジェクトの型に基づいています。

以下に簡単な例を示します:

#include <iostream>
using namespace std;

class Animal {
public:
virtual void makeSound() {
cout << "The animal makes a sound" << endl;
}
};

class Dog : public Animal {
public:
void makeSound() override {
cout << "The dog barks: Woof!" << endl;
}
};

class Cat : public Animal {
public:
void makeSound() override {
cout << "The cat meows: Meow!" << endl;
}
};

int main() {
Animal* animal1 = new Dog();
Animal* animal2 = new Cat();

animal1->makeSound();  // 出力: The dog barks: Woof!
animal2->makeSound();  // 出力: The cat meows: Meow!

delete animal1;
delete animal2;
return 0;
}

これを分解して見ていきましょう:

  1. ベースクラス Animal に仮想関数 makeSound() があります。
  2. それぞれの派生クラス DogCatmakeSound() 関数をオーバーライドします。
  3. main() 内で Animal* 型のポインタを作成し、それらに DogCat のオブジェクトを割り当てます。
  4. makeSound() を呼び出すと、プログラムは実際のオブジェクト型に基づいて正しいバージョンを呼び出します、ポインタの型ではなく。

これが仮想関数と多態性の魔法です!

'virtual' キーワード

ここで virtual キーワードは非常に重要です。これは、この関数が派生クラスでオーバーライドされる可能性があることをコンパイラに教えます。これがなければ、プログラムは常にベースクラスのバージョンの関数を呼び出すでしょう。

純粋仮想関数

次に、純粋仮想関数について少しレベルアップしましょう。

純粋仮想関数とは?

純粋仮想関数は、ベースクラスに実装がない仮想関数です。関数宣言に 0 を割り当てることで宣言されます。

以下に例を示します:

#include <iostream>
using namespace std;

class Shape {
public:
virtual double area() = 0;  // 純粋仮想関数
};

class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) {}
double area() override {
return 3.14159 * radius * radius;
}
};

class Rectangle : public Shape {
private:
double length, width;
public:
Rectangle(double l, double w) : length(l), width(w) {}
double area() override {
return length * width;
}
};

int main() {
Shape* shape1 = new Circle(5);
Shape* shape2 = new Rectangle(4, 5);

cout << "Circle area: " << shape1->area() << endl;
cout << "Rectangle area: " << shape2->area() << endl;

delete shape1;
delete shape2;
return 0;
}

この例では:

  1. Shape は抽象基本クラスで、純粋仮想関数 area() を持っています。
  2. CircleRectangle は具体的なクラスで、Shape を継承し、独自の実装の area() を提供します。
  3. Shape ポインタを作成し、CircleRectangle オブジェクトに割り当てます。
  4. area() を呼び出すと、実際のオブジェクト型に基づいて正しいバージョンが呼び出されます。

抽象クラス

少なくとも1つの純粋仮想関数を持つクラスは抽象クラスと呼ばれます。抽象クラスのオブジェクトを作成することはできませんが、抽象クラス型のポインタや参照を使用することはできます。

多態性を使用する理由は?

  1. 柔軟性: 複数の型のオブジェクトと共に動作するコードを書くことができます。
  2. 拡張性: 新しい派生クラスを追加する際に既存のコードを変更する必要はありません。
  3. 単純性: 異なるオブジェクトを一貫して扱うことでコードを簡素化できます。

多態性で一般的に使用されるメソッド

以下は、C++の多態性で一般的に使用されるメソッドの一覧です:

メソッド 説明
virtual ベースクラスで仮想関数を宣言するためのキーワード
override 派生クラスでベースクラスの関数をオーバーライドしていることを示すキーワード
= 0 純粋仮想関数を宣言するために使用
dynamic_cast 多態的クラス階層で安全にダウンキャストを行うために使用
typeid 実行時に型情報を取得するために使用

結論

多態性はC++における強力な機能で、柔軟で拡張性のあるコードを可能にします。仮想関数と純粋仮想関数を使用して、互換性のあるクラス階層を作成することで、よりモジュール化された、保守しやすいコードを作成することができます。

覚えることをお勧めします、新しいスキルを学ぶのと同じに、多態性をマスターするには練習が必要です。今すぐ理解できなくても心配しないでください — コードを書き続け、実験を続けることで、いつかプロのように多態性を使いこなすことができるでしょう!

Credits: Image by storyset