在多个 DLL 中分离 class 个实现

Separate class implementations in multiple DLLs

我正在尝试创建一个系统,该系统在每个 dll 中使用 class 的不同实现。所以我有一个 VertexBufferObject class,它有一个实现和私有方法(也许是该 DLL 严格使用的方法)。但是主要可执行文件只会使用一组特定的方法。例如:

在openglGraphics.dll中:

class VertexBufferObject {
    private:
        // Unexported data
        uint vbo;

        // Exported data (won't actually use this though)
        std::vector<Vec3> arr;
    public:
        // Unexported methods
        IDirect3DVertexBuffer9 *getVBO();

        // Exported methods
        virtual void Build(Vec2 array);
        virtual void Build(Vec3 array);
        virtual void Unbind();
        ~VertexBufferObject();
};

在directXGraphics.dll中:

class VertexBufferObject {
    private:
        // Unexported data
        IDirect3DVertexBuffer9 vbo;

        // Exported data (won't actually use this though)
        std::vector<Vec3> arr;
    public:
        // Unexported methods
        IDirect3DVertexBuffer9 *getVBO();

        // Exported methods
        virtual void Build(Vec2 array);
        virtual void Build(Vec3 array);
        virtual void Unbind();
        ~VertexBufferObject();
};

最后,可执行文件可以使用工厂函数并创建 class 的导出方法,但不能创建特定于 dll 的方法。这可能吗?还有其他方法可以处理吗? (此外,如果您对图形 API 感兴趣并且可以发现其中的任何缺陷,那会很酷,但不是问题的重点。)

当然可以在 DLL 端执行此操作:您的每个实现都将在一个单独的编译单元和一个单独的 DLL,甚至一个单独的项目中。但是...

但这在DLL客户端是行不通的,因为客户端必须知道对象的定义,而ODR规则要求只有一个定义。

因此,您最好选择经过修改且更具可持续性的设计。

选项1:use继承public接口

class IVertexBuffer {
    public:
        // Exported methods
        virtual void Build(Vec2 array)=0;
        virtual void Build(Vec3 array)=0;
        virtual void Unbind()=0;
        virtual ~IVertexBuffer();     // virtual function ==> virtual dtor !!!
};

在openglGraphics.dll中:

class VertexBufferGLObject : public IVertexBuffer {
    private:
        uint vbo;
        std::vector<Vec3> arr;
    public:
        // Unexported methods
        IDirect3DVertexBuffer9 *getVBO();

        // Exported methods of the interface
        void Build(Vec2 array) override;
        void Build(Vec3 array) override;
        void Unbind() override;
        ~VertexBufferObject();
};

工厂可以根据软件配置加载正确的 dll,并创建 VertexBufferGLObject ,而客户端代码只会使用多态基础 class。

然而,这意味着客户端代码仅使用指针和引用。如果需要复制,如果你想避免切片的风险,你需要使用 clone() 函数。

选项 2:更灵活地隐藏内部结构

您也可以使用 PIMPL idiom also called compilation firewall

想法如下:

class IVertexBufferImpl;  // you need to define this only in the implementation 
class VertexBufferObject {
    private: 
        IVertexBufferImpl *myobject; 
    public:
        // Exported methods
        virtual void Build(Vec2 array);
        virtual void Build(Vec3 array);
        virtual void Unbind();
        virtual ~VertexBufferObject();  
        // + rule of 3 
};

你的间接水平更高了。但是这个 class 的实现会将调用转发给 IVertexBuffer 对象,您可以像选项 1 中那样使用工厂创建私有对象。优点是客户端可以将 VertexBufferObject 用作​​任何其他对象(通过值或参考):它在 encapsulation/isolation 中更进一步。

方案三:使用桥梁设计模式

bride design pattern 旨在将抽象与其实现解耦。

它的工作方式与选项2类似,但意图不同:目标不是隐藏实现,而是解耦,以避免双方的推导和细化:在抽象和在实施方面。