2010-08-25

C++におけるoverloadとoverrideとhiding

2chのC++相談室で、色々と議論が巻き起こっているようだ。少なくとも一人は、規格を参照しているようである。C++の規格上の、overloadとoverrideとhidingについて、分かりやすくまとめてみた。オーバーロードとオーバーライドは、単に音訳した際に、日本人にとって音が非常に似ているという問題に過ぎないのだが。

同じ名前で、他のシグネチャの違う関数セットのことを、関数のオーバーロード(overload)という。

void f(int) ;
void f(double) ;

この例では、void f(int)とvoid f(double)は、オーバーロードされた関数のセットである。

Derived classがBase classと同じvirtual関数を宣言しているとき、Derived classのvirtual関数は、Base classの同virtual関数を、オーバーライド(override)しているという。

struct Base
{
    virtual void f() {}
} ;

struct Derived : Base
{
    virtual void f() {}// override
} ;

Derived classのメンバー名に対し、同名のBase classのメンバーがある場合、Derived classのメンバーは、Base classのメンバーを隠している(hiding)という。

struct Base
{
    void f(int) ;
    int value ;
} ;

struct Derived : Base
{
    void f(double) ;
    double value ;
} ;

int main()
{
    Derived d ;

    d.f(0) ; // void Derived::f(dobule)を呼ぶ
    d.value ; // double Derived::valueである
}

結局これは、Derived classスコープのメンバーである名前が、Base classスコープのメンバーの名前を隠しているに過ぎない。同じことは、クラス以外のスコープでも起こる。

int value ; // グローバルスコープの変数

void f()
{// 関数fのブロックスコープ
    int value ; // ::valueを隠す。
    value ; // ローカル変数のvalue
}

virtual関数はoverrideするものである。Derived classの非virtualなメンバー関数に対し、同名のBase classの非virtualなメンバー関数がある場合、それは単に、名前を隠しているだけである。

今執筆中のC++本では、これらの用語は正しく使うつもりだが、ことさらに用語を解説したりはしない。ただし、どうも「引数」という言葉は、parameter(仮引数)とargument(実引数)をそこまで厳密に区別しなくても、問題のない場合が多いので、単に引数とだけ書いている箇所が多数ある。最初は厳密に書き分けようとしたが、すぐに、意味のないことだと気がついた。そこまで厳密に知りたければ、最初から規格を読むべきなのだ。

No comments: