オーバーロードと継承

http://www.geocities.jp/ky_webid/cpp/language/011.html

なんか色々な機能が一気に流れ込んできていろいろ頭がこんがらがってきたんですが・・・。なんとかやりましょう。

継承間でのオーバーロードはできません。

どういうことかというと下記の例を見てください。

#include <iostream>

class CBase {
public:
    void func(int);
};

class CSub : public CBase {
public:
    void func(char*);
};

void CBase::func (int num) {
    std::cout << num << std::endl;
}

void CSub::func (char *str) {
    std::cout << str << std::endl;
}

int main () {
    CSub obj;
    obj.func("bar");
    obj.func(100);
    return 0;
}

この処理はコンパイルが通りません。「obj.func(100)」がエラーとなります。

CBaseのfunc(int)とCSubのfunc(char*)でオーバーロードが適用されそうに見えますが、継承をまたいだ場合はオーバーロードにならずに、関数の上書き、もしくはオーバーライド扱いになります。よってCSub型の変数objはfunc(char*)なので「obj.func(100)」がコンパイルエラーとなるわけなのです。

また同じ理由から、以下のような処理も通りません。

int main () {
    CSub obj;
    CBase *p = &obj;
    p->func("bar");
    return 0;
}

CBaseにはfunc(char*)のメンバ関数は存在しないのでコンパイルエラーとなります。

更に言えばfuncがvirtual付きの仮想関数の場合もうまくいきません。

#include <iostream>

class CBase {
public:
    virtual void func(int);
    void call ();
};

class CSub : public CBase {
public:
    void func(char*);
};

void CBase::func (int num) {
    std::cout << num << std::endl;
}

void CBase::call () {
    func(100);
}

void CSub::func (char *str) {
    std::cout << str << std::endl;
}

int main () {
    CSub obj;
    obj.call();
    return 0;
}
$ main
100

コンパイルは通りますが、結局挙動は違います。

virtualで仮想関数化した場合、その引数の型まで一致していないと、オーバーライドになりません。

上記の場合、CSubはfunc(char*)なのでCBaseのfunc(int)とはまったく関係が無いのでオーバーライド扱いにならないということになり、call関数を呼び出したところで、CBaseのfuncが呼ばれる羽目になるわけです。