我有一个关于在C++库中隐藏接口(interface)详细信息的问题。以下示例说明了该问题:

假设w有一个名为 ISystem 的类,它公开了Init,Run,Tick,Shutdown,GetXXXSubSystem等方法。
X是各种接口(interface)的指针,例如:ISoundSystem,IInputSystem

我们也有ISystem的具体实现,例如:
Win32System,OSXSystem 等。

这些特定的实现使用pimpl习惯用法来隐藏内部结构
例如Win32System实例化 Win32RawInputSystem
担任输入系统经理。

所有这些管理器都具有自己的Init,Run,Tick和Shutdown方法
它们不是接口(interface)的一部分(仅是具体的实现),它们是由具体的系统实现运行和管理的。

调用GetXXXSubSystem的用户获取的接口(interface)指针没有这些方法(Init等),但是
仍然他可以把他的指针投向具体的实现
并触发他不应该访问的方法,例如Init Run Tick等。

问题是,是否可以以某种方式隐藏具体的类(class)?我试图做那些方法
在具体的实现中受到保护,并在类型上将类最终作为模板,但最终似乎是 friend ,但这似乎很容易,并且现有的hack无法在VC11中使用。

我认为正确的唯一方法是从 header 转移具体的实现声明
放入Win32System类的cpp文件中,但是我看到这样做的巨大缺点(即使不确定这样做是否可行),因为这样每个子系统
也必须是此cpp文件的一部分,这将成为可维护性的噩梦。

我正在考虑的另一个解决方案是使用工厂方法

(RawInput.h)
IInputSystem* CreateRawInputSystem();

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

并将类的定义移动到cpp文件,但是,如何从库的其他部分(即Win32System impl)访问这种类型?

是否可以从其他.cpp文件中包含.cpp文件?

在此先感谢您提供任何提示。

最佳答案

如果要在此处开发库,则可以选择不导出不想公开的具体类的头文件。您不能转换为没有定义的类。

范例:
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 /文件夹中的 header 。客户端仍然可以使用该库,但是他们永远不能将IInputSystem*转换为Win32RawInputSystem*,因为它们没有该 header 。因此,该库的用户可以在Foo()上调用Bar()IInputSystem*,但他们永远无法调用Run()

关于c++ - 接口(interface),隐藏C++中的具体实现细节,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12331752/

10-11 15:58