C++ 如何通过 header 正确公开共享库
C++ How to correctly expose a Shared Library via header
我设计并开发了一个SHARED 库并想发布它,但我不想公开私有方法和私有属性。
这是我尝试过但没有成功的方法:
完整header,用于构建库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时使用的header与这个类似,但没有私人部分。
当我调用函数 initialize
时,属性 attribute03
和 attribute04
设置正确,我可以使用它们直到某个时刻。
所有这些场景的实际问题
我不知道为什么,但在某些时候,attribute03
和 attribute04
只是得到一些垃圾,我有一个 SIGABRT
结束执行。
已编辑(第二次)
经过一些评论,我进入了以下 PIMPL 解决方案,现在它工作正常。
headermy_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();
};
}
NEW full header 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 时,它与所有旧二进制文件兼容,因为 public 接口没有改变。
The header I designed to use when sharing mylib.so with others is similar to this one, but without the private section.
您用于构建.so 共享库的header 应该与您向客户端公开的header 相同。一个不能有私有成员,另一个不能有。客户端不会将私有成员视为 class 的一部分,但在执行函数时,它会尝试使用不属于实例的内存。
如前所述,PIMPL 是一种常用的解决方案。在您的 class 的私人部分中,您可以拥有一个 MyClassData* mData;宣言。在您的 .cpp 文件中,您可以定义结构 MyClassData,并启动其成员。在构造函数中,为mData分配内存,在析构函数中删除内存。
我设计并开发了一个SHARED 库并想发布它,但我不想公开私有方法和私有属性。
这是我尝试过但没有成功的方法:
完整header,用于构建库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时使用的header与这个类似,但没有私人部分。
当我调用函数 initialize
时,属性 attribute03
和 attribute04
设置正确,我可以使用它们直到某个时刻。
所有这些场景的实际问题
我不知道为什么,但在某些时候,attribute03
和 attribute04
只是得到一些垃圾,我有一个 SIGABRT
结束执行。
已编辑(第二次)
经过一些评论,我进入了以下 PIMPL 解决方案,现在它工作正常。
headermy_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();
};
}
NEW full header 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 时,它与所有旧二进制文件兼容,因为 public 接口没有改变。
The header I designed to use when sharing mylib.so with others is similar to this one, but without the private section.
您用于构建.so 共享库的header 应该与您向客户端公开的header 相同。一个不能有私有成员,另一个不能有。客户端不会将私有成员视为 class 的一部分,但在执行函数时,它会尝试使用不属于实例的内存。
如前所述,PIMPL 是一种常用的解决方案。在您的 class 的私人部分中,您可以拥有一个 MyClassData* mData;宣言。在您的 .cpp 文件中,您可以定义结构 MyClassData,并启动其成员。在构造函数中,为mData分配内存,在析构函数中删除内存。