隐藏c++库的私有成员
Hiding private members of c++ library
我写了一个库(不管它做什么),它显然有它的头文件。现在,我想隐藏该头文件的私有元素,所以如果我向某人提供我的库,他/她应该只看到公共成员(最好没有类定义,只有函数定义)。一种方法是创建C样式的头,它将包含某种"init"方法,该方法将用于创建库的实际类的实例,用户必须将该对象的指针传递给每个函数才能完成这项工作。
这是一个好的做法吗?
有没有其他被公众接受的方式来做这样的事情?
提前谢谢。
除了工厂模式(在我看来,这可能会变得难以处理)之外,您还可以将您的私人成员隐藏在PIMPL(指向IMPLementation的指针)后面:
// Interface.hpp
class Implementation;
class Interface {
public:
Interface() : pimpl(new Implementation()) {}
void publicMethod();
private:
std::unique_ptr<Implementation> pimpl;
};
// Interface.cpp
class Implementation {
public:
void PrivateMember();
};
void Interface::publicMethod() { pimpl->PrivateMember(); }
这样做的优点是以单个指针间接寻址为代价隐藏实现,与典型的基于继承的Factory模式没有太大区别。
这也可以是ABI稳定的。对实现的更改不会影响链接,因为程序的其余部分永远看不到任何更改。例如,在实现共享对象时,这是一个很好的模式。
这也是一个常见的C++习惯用法,所以其他C++程序员会毫无疑问地识别它。
在一个将遵循Singleton模式的类的情况下,您可以完全避免暴露PIMPL,只需在.cpp
文件中的匿名namespace
中编写整个实现,在那里您可以放置任意多的状态和私有函数,甚至不需要在接口中暗示它。
您可以创建一个公开可见的接口。创建一个带有您想要公开的函数的抽象类,然后让您的实现对其进行扩展
例如,一个接口:
class Interface {
public:
virtual void publicMethod() = 0;
...
};
以及实现:
class Implementation : Interface {
public:
virtual void publicMethod();
private:
int hiddenMethod();
};
然后只导出"接口"的符号。现在,为了让库的用户获得实际实现的Interface实例,您需要提供一个工厂:
class Factory {
public:
//can create and return an Implementation pointer, but caller will get an Interface pointer
std::shared_ptr<Interface> getImplementationInstance();
}
根据Eric Finn的回答,您只需声明一个interface
类来保存您的所有被认为是API的公共方法,并隐藏继承interface
类的实现类中的所有实现和私有成员/方法,下面是示例:
您的头文件:my_api.h
// your API in header file
// my_api.h
class interface {
public:
static interface* CreateInstance();
virtual void draw() = 0;
virtual void set(int) = 0;
};
您的实现(共享库):myapi.cpp(当您将其作为共享库时,用户不会看到它)所以你可以在这里隐藏所有的实现和私有方法/成员
#include "my_api.h"
// implementation -> in .cc file
class implementation : public interface {
int private_int_;
void ReportValue_();
public:
implementation();
void draw();
void set(int new_int);
};
implementation::implementation() {
// your actual constructor goes here
}
void implementation::draw() {
cout << "Implementation class draws something" << endl;
ReportValue_();
}
void implementation::ReportValue_() {
cout << "Private value is: " << private_int_ << endl;
}
void implementation::set(int new_int) {
private_int_ = new_int;
}
interface* interface::CreateInstance() {
return new implementation;
}
用户如何使用您的API:
#include <iostream>
#include "my_api.h"
int main(int argc, const char * argv[])
{
using namespace std;
interface* a; interface* b;
a = interface::CreateInstance();
a->set(1);
b = interface::CreateInstance();
b->set(2);
b->draw();
a->draw();
return 0;
}
输出:
Implementation class draws
Private int is: 2
Implementation class draws
Private int is: 1
在这种模式中,你的api只是一个抽象类,它的工作方式就像工厂一样,你也可以在不同的类中实现虚拟方法,并指定你想调用哪个实例。
我认为您需要创建动态链接库(dll)。
请快速查看此链接:
您可能需要了解信封/信件习惯用法、桥接设计模式或代理模式。基本上,您将创建一个外部(公共)类,它只会将您的公共方法调用转发到内部(私有)类。您的InnerClass.h标头只需要对OuterClass.cpp和InnerClass.cp源文件可见/已知即可。
这些模式中的每一个都提供了一种将实现与接口分离的机制,这样调用者就不会耦合到实现。有时,这是为了减少编译器对大型C++项目的依赖。想要这样做的另一个常见原因是,当您想要隐藏实现细节,以便调用方只看到一个不透明的指针时。
======= OuterClass.h =====
class InnerClass; // forward declaration is all that's needed
class OuterClass {
private:
InnerClass *pInner;
public:
InnerClass();
bool doSomething();
};
======= OuterClass.cpp ======
#include "OuterClass.h"
#include "InnerClass.h"
OuterClass::OuterClass() :
pInner(new InnerClass())
{
}
bool OuterClass::doSomething()
{
return pInner->doSomething();
}
实际上有一种方法可以做到这一点而不必使用类。我遇到了同样的问题,这里有一个非常简单的解决方案:
只需将您的私人物品放入.cpp文件即可。你的头文件看起来像这样:
// These will be visible to everyone using this library
void function();
int someNumber = 2;
和.cpp文件:
void function() {
// whatever this function does
}
// This will be only visible to the library itself
static void secretFunction() {
doSomeSecretStuff;
}
static int PIN = 1234;
// Okay, if you write this Number into your library and expect it to be safe,
// then screw you, but at least no one will be able to access it with code
当从外部调用"public"函数时,您现在不再需要该类的任何实例:只需将库放在正确的目录中并包含它,但您可能已经处理好了),并在Lib.h
文件中按函数名称调用函数。在这个例子中,它看起来像这样:
#include "Lib.h"
int main(int argc, const char * argv[]) {
function();
return 0;
}
感谢Edgar Bonet帮助我在Arduino Stackeexchange上找到此解决方案!
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 嵌套在类中时无法设置成员数据
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 将函数类成员映射到类本身内部
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- 多成员Constexpr结构初始化
- 我们可以访问一个不存在的联盟的成员吗