C++継承における名前の衝突と解決方法

継承クラス間での名前競合

1. 派生クラスにおける同名メンバー変数の定義

2. 派生クラスのメンバーによる基底クラス同名メンバーの隠蔽

3. 基底クラスの同名メンバーの存在維持

4. スコープ解決演算子(::)による基底クラス同名メンバーへのアクセス

#include <iostream>

using namespace std;

class Base
{
public:
    int value;
    Base()
    {
        cout << "Base.valueのアドレス: " << &value << endl;
    }
};

class Derived : public Base
{
public:
    int value;
    Derived()
    {
        cout << "Derived.valueのアドレス: " << &value << endl;
    }
};

int main()
{
    Derived d;
    d.value = 2000;//派生クラスのメンバーにアクセス
    d.Base::value = 200;//スコープ解決演算子で基底クラスの同名メンバーにアクセス
    
    cout << endl;

    cout << "d.valueのアドレス: " << &d.value << endl;
    cout << "d.valueの値: " << d.value << endl;

    cout << endl;

    cout << "d.Base::valueのアドレス: " << &d.Base::value << endl;
    cout << "d.Base::valueの値: " << d.Base::value << endl;
    
    return 0;
}

//実行結果
/*
Base.valueのアドレス: 0x7ffee1b2b8d8
Derived.valueのアドレス: 0x7ffee1b2b8dc

d.valueのアドレス: 0x7ffee1b2b8dc
d.valueの値: 2000

d.Base::valueのアドレス: 0x7ffee1b2b8d8
d.Base::valueの値: 200
*/

オーバーロードの再考察

1. クラスメンバー関数のオーバーロード

(1)オーバーロード関数は本質的に異なる複数の関数

(2)関数名とパラメータリストが一意の識別子

(3)関数オーバーロードは同一スコープ内でのみ発生

2. 基底クラスと派生クラスの同名関数

(1)派生クラスの関数が基底クラスの関数を隠蔽

(2)派生クラスは基底クラスのメンバー関数をオーバーロードできない

(3)スコープ解決演算子で基底クラスの同名関数にアクセス

(4)派生クラスは基底クラスと完全に同一の関数を定義可能

#include <iostream>

using namespace std;

class Base
{
public:
    int value;
    void increment(int v)
    {
        value += v;
    }

    void increment(int x, int y)
    {
        value += (x + y);
    }
};

class Derived : public Base
{
public:
    int value;
    void increment(int v)
    {
        value += v;
    }

    void increment(int x, int y, int z)
    {
        value += (x + y + z);
    }
};

int main()
{
    Derived d;
    d.value = 2000;
    d.Base::value = 200;
    
    cout << "d.value = " << d.value << endl;
    cout << "d.Base::value = " << d.Base::value << endl;

    d.increment(2);
    d.Base::increment(2);
    cout << "d.value = " << d.value << endl;
    cout << "d.Base::value = " << d.Base::value << endl;

//    d.increment(2, 3); //コンパイルエラー:派生クラスにこの関数は存在しない
    //派生クラスに一つでも同名関数が存在すると、基底クラスの全ての同名関数が隠蔽される
    d.Base::increment(2, 3);
    cout << "d.Base::value = " << d.Base::value << endl;
    
    return 0;
}

//実行結果
/*
d.value = 2000
d.Base::value = 200
d.value = 2002
d.Base::value = 202
d.Base::value = 207
*/

まとめ

1. 派生クラスは基底クラスの同名メンバーを定義できる

2. 派生クラスのメンバーは基底クラスの同名メンバーを隠蔽する

3. 派生クラスと基底クラスの関数はオーバーロード関係を構成しない

4. 派生クラスは基底クラスと完全に同一のメンバー関数を定義できる

5. スコープ解決演算子で基底クラスの同名メンバーにアクセスする

タグ: C++ 継承 オーバーロード スコープ解決演算子 名前隠蔽

6月16日 22:59 投稿