C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++における関数のオーバーロードとオーバーライドの違い

C++には、同じ名前の関数を扱う仕組みとして「オーバーロード(多重定義)」と「オーバーライド(上書き)」があります。この2つは名前が似ているため混同されやすいですが、目的も動作のタイミングもまったく異なります。本記事では、それぞれの特徴と違いをわかりやすく解説します。

オーバーロード(Overloading)とは

オーバーロードとは、同じ名前の関数を、引数の個数や型を変えて複数定義できる機能です。

  • 特別なキーワードは不要で、通常の関数定義と同じように記述します。
  • 関数のシグネチャ(プロトタイプ)は、引数の個数または型が異なっている必要があります。戻り値の型だけが異なる場合はオーバーロードできません。
  • どの関数が呼び出されるかはコンパイル時に決定されます(静的結合・早期バインディング)。
  • コンストラクタはオーバーロードできます。
  • デストラクタは引数を持たないため、オーバーロードできません。
  • 呼び出される関数のバージョンは、実引数の個数や型によって決まります。
  • 同じ名前のまま、引数の個数や型が異なる関数を再定義する形になります。

オーバーライド(Overriding)とは

オーバーライドとは、基底クラスで定義された仮想関数を、派生クラスで同じシグネチャのまま再定義する仕組みです。

  • 関数のシグネチャ(戻り値の型・関数名・引数)は、基底クラスと完全に同一である必要があります。
  • 実際に呼び出される関数は実行時に決定されます(動的結合・遅延バインディング)。これがオーバーライドが「遅延バインディング」と呼ばれる理由です。
  • オーバーライドの対象となるのは仮想関数です。基底クラス側の関数には virtual キーワードを付けます。
  • 基底クラスのポインタや参照に派生クラスのオブジェクトを代入すると、そのポインタ経由で呼び出されるのは、実際のオブジェクトの型に応じた関数になります。
  • デストラクタは virtual にすることでオーバーライド可能です。継承を前提としたクラスでは、基底クラスのデストラクタを仮想関数にすることが推奨されます。
  • C++11以降では、派生クラス側で override 指定子を付けることで、オーバーライドの意図を明示でき、シグネチャの誤りをコンパイラが検出してくれます。

コード例

#include <iostream>

// --- オーバーロードの例 ---
int add(int a, int b) { return a + b; }
double add(double a, double b) { return a + b; }

class Base {
public:
    virtual void show() { std::cout << "Base::show()" << std::endl; }
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    void show() override { std::cout << "Derived::show()" << std::endl; }
};

int main() {
    add(1, 2);      // int版が呼ばれる(コンパイル時に決定)
    add(1.5, 2.5);  // double版が呼ばれる

    Base* p = new Derived();
    p->show();      // Derived::show() が呼ばれる(実行時に決定)
    delete p;
    return 0;
}

違いの比較表

項目オーバーロードオーバーライド
発生する場所同一クラス内(同一スコープ内)継承関係にある基底・派生クラス間
関数シグネチャ引数の個数か型が異なる必要がある完全に同一である必要がある
結合のタイミングコンパイル時(早期バインディング)実行時(遅延バインディング)
virtualキーワード不要基底クラス側に必要
コンストラクタオーバーロード可能オーバーライド不可
デストラクタオーバーロード不可virtualにすればオーバーライド可能
ポリモーフィズム静的ポリモーフィズム動的ポリモーフィズム

まとめ

オーバーロードは「同じ名前で引数構成の異なる複数の関数」をコンパイル時に選択する仕組み、オーバーライドは「基底クラスの仮想関数を派生クラスで差し替える」実行時の仕組みです。C++11以降では、オーバーライドの意図を明確にするために override キーワードを使用することがベストプラクティスとされています。両者を正しく使い分けることで、柔軟で保守性の高いC++プログラムを設計できます。

  1. C++のnewキーワードとoperator newの違いをわかりやすく解説

    C++でオブジェクトを生成する際には、メモリ上にブロックを確保し、さらにコンストラクタを呼び出してそのメモリブロックを初期化するという2段階の処理が必要になります。通常、私たちが new キーワードを使ってオブジェクトを作成すると、この2つの処理が連続して実行されます。一方、operator new はメモリ領域の確保だけを行う関数です。本記事では、この2者の違いを具体例とともに詳しく解説します。newキーワードとはnew 演算子は、ヒープ領域へのメモリ割り当てを要求するための特殊な演算子です。十分なメモリが利用可能な場合にのみ、確保されたメモリへのポインタ変数が返されます。通常の new キ

  2. C#におけるメソッドと関数の違い

    C#におけるメソッドと関数の違いC#において、「メソッド」と「関数」は本質的に同じものを指します。ただし、C#では一般的に「メソッド」という用語が使われるのが特徴です。これは、C#がオブジェクト指向言語であり、すべてのコードがクラス内に記述されるためです。つまり、メソッドとは「指定されたクラスに属し、そのクラスを通じて動作する関数」のことを意味します。メソッドとは、ひとつのタスクを実行するためにまとめられたステートメント(文)のグループです。すべてのC#プログラムには、Mainという名前のメソッドを持つクラスが少なくとも1つ含まれており、プログラムの実行は必ずこのMainメソッドから開始されま