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 时,属性 attribute03attribute04 设置正确,我可以使用它们直到某个时刻。

所有这些场景的实际问题

我不知道为什么,但在某些时候,attribute03attribute04 只是得到一些垃圾,我有一个 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 接口没有改变。

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

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分配内存,在析构函数中删除内存。