68555


以下のような抽象クラス Interface1, Interface2 があります。

[code]

    class Interface1
    {
    public:
        virtual void Function() = 0;
    };
    
    class Interface2
    {
    public:
        virtual void Function() = 0;
    };
    
[/code]

これら2つの抽象クラスを多重継承するクラス Implementation があります。

[code]

    class Implementation :
        public Interface1,
        public Interface2
    {
        // Interface1 としての Function() の振る舞いを実装したい
    
        // Interface2 としての Function() 振る舞いを実装したい
    }
    
[/code]

Implementation のコメントの通り、Interface1::Function() と Interaface2::Function()
にそれぞれ異なる実装を与える方法はありますでしょうか?

例えば、Interface1, Interaface2 は以下のように使われます。

[code]

    template<typename T>
    class InterfaceCaller
    {
    public:
        void Register(T* pInterface)
        {
            m_List.push_back(pInterface);
        }
    
        void Call()
        {
            for(auto& interface : m_List)
            {
                interface->Function();
            }
        }
    private:
        std::vector<T*> m_List;
    };
    
[/code]

`InterfaceCaller<Interface1>::Register(Implementation);`
としたとき、`InterfaceCaller<Interface1>::Call()` では、「Interface1 としての Function()
の振る舞い」が呼ばれるようにしたいです。


CC BY-SA 4.0
2020-07-13T08:35:24.730
68548
2020-07-14T04:11:38.907
2020-07-13T08:50:36.307
3475
29926
question
c++
同名の純粋仮想関数を持つ抽象クラスの継承時に、それぞれ異なる実装を記述する方法はありますか?


抽象クラス`Interface1`, `Interface2`に手を入れられない場合、クラス継承関係に中間層を設ける方法が考えられます。

下記コードでは`ProxyInterface1`クラスによって`Interface1::Function`を`Function1`に、`ProxyInterface2`によって`Interface2::Function`を`Function2`に処理委譲し、個別にオーバーライド可能としています。  
Proxyクラスの`Function`オーバーライドでは`final`指定を行うことで、`Implementation::Function`で再度オーバーライドされるミスを防いでいます。

[code]

    class Interface1
    {
    public:
        virtual void Function() = 0;
    };
    
    class Interface2
    {
    public:
        virtual void Function() = 0;
    };
    
    class ProxyInterface1 : public Interface1
    {
        virtual void Function() override final { Function1(); }
        virtual void Function1() = 0;
    };
    
    class ProxyInterface2 : public Interface2
    {
        virtual void Function() override final { Function2(); }
        virtual void Function2() = 0;
    };
    
    class Implementation :
        public ProxyInterface1,
        public ProxyInterface2
    {
        virtual void Function1() override { std::cout << "Interface1::Function\n"; }
        virtual void Function2() override { std::cout << "Interface2::Function\n"; }
    };
    
[/code]

<https://wandbox.org/permlink/jKvkWFYrN2PKmtb6>


CC BY-SA 4.0
2020-07-13T10:49:38.730
68555
2020-07-14T04:11:38.907
2020-07-14T04:11:38.907
49
49
68548
answer


Visual C++の場合、[明示的なオーバーライド](https://docs.microsoft.com/ja-jp/cpp/cpp/explicit-
overrides-cpp?view=vs-2019)という機能が提供されていて、メンバー関数名にクラス名を付与できます。

[code]

    class Implementation :
        public Interface1,
        public Interface2
    {
        // Interface1 としての Function() の振る舞いを実装したい
        void Interface1::Function() override {
            std::cout << "Interface1::Function\n";
        }
    
        // Interface2 としての Function() 振る舞いを実装したい
        void Interface2::Function() override {
            std::cout << "Interface2::Function\n";
        }
    };
    
[/code]

.NET Runtime仕様としてこのような継承が認められているため、それを実現するためにVisual
C++コンパイラにも実装されており、その際、非.NET環境にも同様に記述できるように言語拡張されているようです。


CC BY-SA 4.0
2020-07-13T11:57:46.520
68556
2020-07-13T12:12:59.397
2020-07-13T12:12:59.397
4236
4236
68548
answer