継承時にメンバ変数を上書きした場合

オーバーライド関連で少し気になったので試してみました。

メンバ関数ではなく、メンバ変数を上書きしたらどうなるのかな?と思って以下のコードを書いてみました。

#include <iostream>

class CSuper {
public:
    int m_i;
    CSuper();
    void csuper_call();
};

class CSub : public CSuper {
public:
    int m_i;
    CSub(int);
    void csub_call ();
};

CSuper::CSuper() {
    m_i = 10;
}

void CSuper::csuper_call () {
    std::cout << m_i << std::endl;
}

CSub::CSub(int num) {
    m_i = num;
}

void CSub::csub_call () {
    std::cout << m_i << std::endl;
}

int main () {
    CSub obj(100);
    obj.csuper_call();
    obj.csub_call();
    return 0;
}
10
100

なるほど、やはりクラスごとで別の変数になるんですね。

ということはメンバ関数と同じでvirtualをつけて仮想(変数?)化すればCSuperでもCSubのm_iを参照してくれたりするのかな?と思ってコンパイルしてみたところ、見事にコンパイルエラーになりました。

ということはサブクラス側で同名のメンバ変数を定義してしまったらスーパークラスのメンバ変数にアクセスする手段は無いということになるんでしょうか。スーパークラスで例えばSetIといったような関数が提供されていれば、それ経由で変更可能だとは思いますが、もし無ければもはやアクセスする手段が無いですね。

と、書いてる間に一つ思い浮かんだのが、多態性を利用すればアクセスできるのでは?と思い、試してみました。

int main () {
    CSub obj(100);
    CSuper *sobj = &obj;
    std::cout << sobj->m_i << std::endl;
    return 0;
}
$ main
10

しかし、スーパークラスのm_iにアクセスできたからって何も解決して無いですよね。そもそもCSubのメンバ関数からアクセスができないのが問題であって結局のところCSuper型のメンバ関数しか呼べないので何の意味もありません。また本来メンバ変数はprivateにするのがセオリーということなのでますます意味がないです。


ということでメンバ変数の上書きは危険だという感じで終わりにしたいと思います。