接口,在C++中隐藏具体的实现细节
Interfaces, hiding concrete implementation details in C++
我有一个关于在C++库中隐藏接口细节的问题。下面的例子说明了这个问题:
假设我们有一个名为ISystem的类,它公开了Init、Run、Tick、Shutdown、GetXXXSubSystem等方法其中X是各种接口的指针,如:ISoundSystem,IInputSystem
我们也有ISystem的具体实现,如:Win32System、OSXSystem等
这些特定的实现使用皮条习惯用法来隐藏内部例如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文件中?
提前感谢您的任何提示。
如果您在这里开发库,那么您可以简单地选择不导出不想公开的具体类的头文件。不能强制转换为没有定义的类。
示例:
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
我的项目文件夹/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*
,因为它们没有该标头。因此,该库的用户可以在IInputSystem*
上调用Foo()
和Bar()
,但他们永远无法调用Run()
。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 'using namespace'实现细节的便捷方法(仅标头库)?
- 将C++项目迁移到 Java,保护实现细节
- 如何在C++共享库中隐藏业务对象的实现细节并提供接口
- 接口,在C++中隐藏具体的实现细节
- 无锁单写多读列表的实现细节
- 为初学者澄清C++中类定义和实现的一些细节
- 在它的核心,如何实现提升元组(在提升标头中没有所有额外的细节)
- 如何查找编译器实现细节
- 循环包含在c++头文件中隐藏实现细节的技巧
- 通过减少填充头的数量来隐藏实现细节
- boost::python是如何工作的?对实现细节有什么想法吗?
- Reference_wrapper实现细节
- 内存池背后的常见实现细节是什么?