从静态库中公开一个类
我正在开发一个解析器库,在其中解析数据并将其存储在不同的数据结构中。该库的设计是这样的,它将具有 DataProvider、Parser 和 DataStore 类。 DataStore 是DataProvider 类的成员。消费者需要调用DataProvider中的函数来解析文件并从库中检索数据。
现在,如果我公开 DataProvider 类,那么我还需要公开 DataStore 类,该类向消费者提供实现细节。公开 DataProvider 类的函数的替代方法是什么?我是否应该公开 LoadFile、GetRecords 等函数并在 cpp 内全局创建 DataProvider 对象?
I am developing a parser library where i parse data and store it in different data structures. The design of the library is such that it will have a DataProvider, Parser and DataStore class. The DataStore is a memebr of DataProvider class. The consumer needs to call the functions in the DataProvider to parse the file and to retrieve the data from the library.
Now if i expose the DataProvider class then i need to expose the DataStore class also which gives the implementation details to the consumer. What is the alternative way of exposing the functions of the DataProvider class? Should i expose functions like LoadFile, GetRecords and create the DataProvider object globally inside the cpp?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果用户不必直接使用
DataStore
,则最好不要公开它。您可以通过创建一个“接口”来实现这一点 - 抽象DataProvider
仅包含公共纯虚函数。在内部,有一个DataProviderImp
,它将继承自DataProvider
,并包含实际实现中所需的所有定义和成员。让用户只使用抽象类。这样,您只需将最少的依赖项拖到 API 中。
If the user doesn't have to use the
DataStore
directly, it should better not be exposed. You can achieve that by creating an "interface" - abstractDataProvider
with only public pure virtual functions. Internally, have aDataProviderImp
which will inherit fromDataProvider
, and contain all the required definitions and members that are part of the actual implementation.Let the user work only with the abstract class. This way, you drag only the minimal dependencies into your API.
首先尽量减少需要在标头中公开的信息,因此尽可能使用前向声明、引用和指针(因此只需要前向声明),并尝试使用 PIMPL 习惯用法来隐藏实现。
接下来,您可以构建另一个类,它是系统的外观,它包装了函数的入口点,并使用间接方法来访问包含的元素(例如可从外部访问的数据元素),例如句柄和索引。
Firstly minimize the information that needs to be disclosed in the headers, so use forward declarations, references and pointers where possible (so only a forward declaration is needed), and try to use a PIMPL idiom to hide the implementation.
Next you could build another class that is a facade to the system, which wraps up the entry points to the functions, and use indirect methods to access contained elements (such as data elements accessible externally), such as handles and indexes.
如果担心外部用户可能创建自己的
DataStore
对象,并在DataProvider
上下文之外使用它们,并且他们抱怨您的库不起作用,那么有一个简单的解决方案和一些不太容易的解决方案。简单的解决方案:记录
DataProvider
是您的库的外部接口。这是 C++ 标准库和 Boost 中采用的解决方案。std::map
的接口是头文件。该标头
#includes
的实现文件以及及其附属标头创建的基础数据类型与您无关。您应该只使用
std::map
公共接口。使用内部数据类型,您就会进入未定义行为的世界。像// 类 DataStore 仅供内部使用的注释。使用它,你就会被解雇。
可以起到相当强大的威慑作用。不依赖上述内容的解决方案:通过在
DataProvider
中定义这些子类(例如,您将拥有类DataProvider::DataStore
)并创建这些类来隔离这些子类定义私有/受DataProvider
保护。另一种方法是将DataStore
中的所有内容设为私有/受保护,并使DataProvider
成为友元类。由于您正在提供静态库和标头,因此无论您多么努力地尝试将它们隔离开来,总会有一些令人讨厌的黑客手段来获取您的底层数据和方法。在某些时候,“这仅供内部使用。别戴脏手套!”方法有相当多的优点。
If the concern is that external users might create their own
DataStore
objects, use them outside the context of aDataProvider
, and them complain that your library doesn't work, there is an easy solution and some not so easy solutions.The easy solution: Document that
DataProvider
is the external interface to your library. This is the solution employed in the C++ standard library, and in Boost. The interface tostd::map
is the header file<map>
. The implementation files that that header#includes
, and the underlying data types that<map>
and its subsidiary headers create are none of your business. You should only use thestd::map
public interfaces. Use internal data types and you're off into the world of undefined behavior. Comments like// The class DataStore is for internal use only. Use it and you will be fired.
can be quite a powerful deterrent.A solution that does not rely on the above: Wall off those subsidiary classes by defining them inside
DataProvider
(e.g., you will have classDataProvider::DataStore
) and making those class definitions private/protected toDataProvider
. Another approach is to make everything inDataStore
private/protected, and makeDataProvider
a friend class.Since you are delivering a static library and headers, there will always be some nasty hackish means to get at your underlying data and methods no matter how hard you try to wall them off. At some point, the "This is for internal use only. Keep your dirty mitts off!" approach has quite a bit of merit.