接口,隐藏C ++中的具体实现细节

时间:2012-09-08 14:46:59

标签: c++ oop design-patterns

我有一个关于在C ++库中隐藏接口细节的问题。使用以下示例说明问题:

假设有一个名为 ISystem 的类,它会公开 Init,Run,Tick,Shutdown,GetXXXSubSystem等方法。 其中X是指针,各种接口如: ISoundSystem,IInputSystem

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

这些具体实现使用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文件?

提前感谢任何提示。

1 个答案:

答案 0 :(得分:1)

如果您在这里开发库,那么您只需选择不导出您不想公开的具体类的头文件。您无法转换为您没有定义的类。

示例:
myProjectFolder的/ Src的/导出/ 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的/导出/ IInputSystem.h

#ifndef IINPUTSYSTEM_H
#define IINPUTSYSTEM_H

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

#endif

<强> myProjectFolder的/ Src的/导出/ 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()