1

C++ ライブラリでインターフェイスの詳細を非表示にすることについて質問があります。この問題は、次の例で説明されています。

Init、Run、Tick、Shutdown、GetXXXSubSystem などのメソッドを公開するISystemというクラスがあるとします。 X は、ISoundSystem、IInputSystemなどのさまざまなインターフェイスへのポインターです。

また、Win32System、OSXSystemなどの ISystem の具体的な実装もあります 。

これらの特定の実装は、内部を隠すために pimpl イディオムを使用します。たとえば、Win32System はWin32RawInputSystem を入力システム マネージャーとしてインスタンス化します。

このようなすべてのマネージャーには、インターフェイスの一部ではない独自のInit、Run、Tick、および Shutdownメソッド (具象実装のみ) があり、これらは具象システム実装によって実行および管理されます。

GetXXXSubSystem を呼び出すユーザーは、これらのメソッド (Init など) なしでインターフェイス ポインターを取得しますが、取得したポインターを具体的な実装にキャストし、Init Run Tick などのアクセスできないメソッドをトリガーすることができます。

問題は、どうにかして具象クラスを隠すことができるかということです。具象実装で保護されたこれらのメソッドと、最終的には友達になるタイプのクラスをテンプレートにしようとしましたが、これは禁止されているようで、既存のハックは VC11 では機能しません。

私が正しく知っていると考えることができる唯一の方法は、具体的な実装宣言をヘッダーから Win32System クラスの cpp ファイルに転送することですが、これを行うことには大きな欠点があります (これが機能するかどうかさえわかりません)。この cpp ファイルの一部でもあると、保守性の悪夢になります。

私が考えている別の解決策は、次のようなファクトリメソッドを使用することです

(RawInput.h) 
IInputSystem* CreateRawInputSystem();

(RawInput.cpp)
class RawInput : public IInputSystem {}; ...

クラスの定義を cpp ファイルに移動しますが、ライブラリの他の部分 (つまり、Win32System impl) からこの型にアクセスするにはどうすればよいでしょうか?

他の .cpp ファイルから .cpp ファイルを含めることはできますか?

ヒントをお寄せいただきありがとうございます。

4

1 に答える 1

1

ここでライブラリを開発している場合は、公開したくない具体的なクラスのヘッダー ファイルをエクスポートしないことを選択できます。定義のないクラスにキャストすることはできません。

例:
MyProjectFolder/Src/Export/ISystem.h

#ifndef ISYSTEM_H
#define ISYSTEM_H

#include "IInputSystem.h"

class ISystem
{
public:
    virtual ~ISystem() {};
    virtual void Run()=0;
    virtual IInputSystem* GetInputSystem()=0;
};

#endif

MyProjectFolder/Src/Export/IInputSystem.h

#ifndef IINPUTSYSTEM_H
#define IINPUTSYSTEM_H

class IInputSystem
{
public:
    virtual ~IInputSystem() {};
    virtual void Foo()=0;
    virtual void Bar()=0;
};

#endif

MyProjectFolder/Src/Export/Win32System.h

#ifndef WIN32SYSTEM_H
#define WIN32SYSTEM_H

#include "ISystem.h"

class Win32System : public ISystem
{
public:
    Win32System();
    virtual void Run();
    virtual IInputSystem* GetInputSystem();

private:
    struct impl;
    impl* m_pImpl;
};

#endif

MyProjectFolder/Src/Win32RawInputSystem.h

#ifndef WIN32RAWINPUTSYSTEM_H
#define WIN32RAWINPUTSYSTEM_H

#include "IInputSystem.h"

class Win32RawInputSystem : public IInputSystem
{
public:
    virtual void Foo();
    virtual void Bar();

    virtual void Run(); // you do not want to expose that function
};

#endif

MyProjectFolder/Src/Win32System.cpp

#include "Win32System.h"

#include "Win32RawInputSystem.h"

struct Win32System::impl
{
    Win32RawInputSystem inputSys;
};

Win32System::Win32System()
 : m_pImpl(new impl)
{
}

void Win32System::Run()
{ // run run run
}

IInputSystem* Win32System::GetInputSystem()
{
    return &m_pImpl->inputSys;
}

したがって、プロジェクトをビルドするとき、インクルード検索パスはSrc/だけでなくSrc/Export/にもなります。ライブラリ プロジェクト内から、Win32RawInputSystem を含むすべてのクラスを使用できます。ライブラリをデプロイするときは、 Src/Export/フォルダーにあるヘッダーのみを配布します。クライアントは引き続きライブラリを使用できますが、そのヘッダーがないためキャストできませんIInputSystem*Win32RawInputSystem*したがって、そのライブラリのユーザーは で と をFoo()呼び出すBar()ことIInputSystem*ができますが、 を呼び出すことはできませんRun()

于 2012-09-08T17:23:56.173 に答える