C++ 如何通过标头正确公开共享库

C++ How to correctly expose a Shared Library via header

本文关键字:共享 何通过 C++      更新时间:2023-10-16

我已经设计并开发了一个共享库,并希望分发它,但我不想公开私有方法和私有属性。

这是我尝试过但没有成功的方法:

完整标头,用于构建库 mylib.so:

namespace MYNAMESPACE{
enum class MyReturnCode {
Success = 1,
MyRetCode01,
MyRetCode02
};
class MyException {
public:
MyException(
MYNAMESPACE::MyReturnCode _code,
std::string _message);
MYNAMESPACE::MyReturnCode code;
std::string message;
};
class MyClass {
public:     
MyClass();
~MyClass();
void initialize();
std::string function01();
std::string function02(); 
int attribute01;
float attribute02;     
private:
std::string function03();
int attribute03;
float attribute04;
};
}

我设计用于与他人共享 mylib.so 的标题与此类似,但没有私有部分。

当我调用函数initialize时,属性attribute03attribute04设置正确,我可以使用它们直到某个点。

所有这些场景的实际问题

我不知道为什么,但在某些时候,attribute03attribute04只是得到一些垃圾,我有一个结束处决的SIGABRT

已编辑(第2次)

经过一些评论,我进入了以下PIMPL解决方案,现在它工作正常。

标头 my_class_api.hpp,用于与 mylib.so 一起分发

#include <memory>
namespace MY_API {
class MyClassAPI {
public:     
virtual ~MyClassAPI() {};
virtual void initialize() = 0;
virtual std::string function01() = 0;
virtual std::string function02() = 0; 
static std::shared_ptr<MyClassAPI> get_my_api();
};
}

新的完整标头 my_class.hpp,用于构建库 mylib.so:

#include "my_class_api.hpp"
namespace MYNAMESPACE{
class MyClass : public MY_API::MyClassAPI {
public:     
MyClass();
~MyClass() override;
void initialize() override;
std::string function01() override;
std::string function02() override; 
private:
std::string function03();
int attribute03;
float attribute04;
};
}

实现文件my_class.cpp

#include "my_class.hpp"
namespace MY_API {
std::shared_ptr<MyClassAPI> MyClassAPI::get_my_api() {
return std::make_shared<MYNAMESPACE::MyClass>();
}
}
namespace MYNAMESPACE {
MyClass::MyClass() { }
MyClass::~MyClass() { }
void MyClass::initialize() { }
std::string MyClass::function01() { }
std::string MyClass::function02() { }
}

感谢所有帮助过我的人!我希望这个例子也能帮助其他人。

如上所述,PIMPL是最好的解决方案。 例如,Qt在其所有类上使用PIMPL来确保二进制兼容性。 也就是说,当安装较新版本的 DLL 时,它与所有旧二进制文件兼容,因为公共接口不会更改。

https://en.cppreference.com/w/cpp/language/pimpl

我设计在与他人共享 mylib.so 时使用的标题与此类似,但没有私有部分。

用于生成 .so 共享库的标头应与向客户端公开的标头相同。一个不能有私人成员,另一个不能有私人成员。客户端不会将私有成员视为类的一部分,但在执行函数时,它会尝试使用不属于实例的内存。

如前所述,PIMPL是一种常用的解决方案。在班级的私人部分,您可以拥有 MyClassData* mData;声明。在.cpp文件中,可以定义结构 MyClassData,并启动其成员。在构造函数中,将内存分配给 mData,在析构函数中删除内存。