はじめに
C++のオーバーライド(override)は、基底クラスの仮想関数を派生クラスで再定義する際に使われる重要な概念です。オーバーライドを正しく理解し使うことで、ポリモーフィズム(多態性)を効果的に活用できます。
基本的なオーバーライドの使い方について下記に記します。
オーバーライドの基本
オーバーライドは、基底クラスに定義された仮想関数を派生クラスで再定義することです。これにより、基底クラスのポインタや参照を使っても、実際には派生クラスの関数が呼び出されます。
基本的な例
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base class show function" << std::endl;
}
};
class Derived : public Base {
public:
void show() override { // オーバーライド
std::cout << "Derived class show function" << std::endl;
}
};
int main() {
Base* basePtr;
Derived derivedObj;
basePtr = &derivedObj;
basePtr->show(); // "Derived class show function" が出力される
return 0;
}
オーバーライドのポイント
-
virtualキーワード: 基底クラスの関数には
virtual
キーワードをつけます。これにより、その関数が仮想関数であることを明示します。 -
override指定子: 派生クラスで関数をオーバーライドする際には、
override
指定子を使います。これにより、コンパイラはその関数が基底クラスの仮想関数を正しくオーバーライドしていることをチェックできます。 - 関数のシグネチャ: オーバーライドする関数は、基底クラスの関数と同じシグネチャ(引数の型や数、戻り値の型)を持つ必要があります。
関数のシグネチャの一致
基底クラスと派生クラスで関数のシグネチャが一致しない場合、オーバーライドではなくオーバーロード(関数の多重定義)と見なされることがあります。例えば、引数の型や数が異なると、別の関数として扱われます。
class Base {
public:
virtual void show(int x) {
std::cout << "Base class show function with int" << std::endl;
}
};
class Derived : public Base {
public:
void show(int x) override { // これで正しくオーバーライドされる
std::cout << "Derived class show function with int" << std::endl;
}
// void show(double x) { // これはオーバーライドではなく、オーバーロードになる
// std::cout << "Derived class show function with double" << std::endl;
// }
};
その他の注意点
- アクセス指定子: オーバーライドする関数のアクセス指定子(public, protected, private)は基底クラスとは異なっても構いません。
- デストラクタのオーバーライド: 仮想デストラクタを持つことが推奨されます。これにより、基底クラスのポインタで動的に確保された派生クラスのオブジェクトが正しく解放されます。
class Base {
public:
virtual ~Base() {
std::cout << "Base destructor" << std::endl;
}
};
class Derived : public Base {
public:
~Derived() override {
std::cout << "Derived destructor" << std::endl;
}
};
まとめ
オーバーライドは、C++でポリモーフィズムを実現するための重要な機能です。基底クラスの仮想関数を派生クラスで再定義することで、基底クラスのポインタや参照を通じて派生クラスの機能を呼び出すことができます。正しくオーバーライドするためには、関数のシグネチャが一致すること、override
指定子を使うことが重要です。