C++ C++;DLL:不公开整个类

C++ C++;DLL:不公开整个类,c++,C++,如何“隐藏”类的某些部分,以便使用库的人不必包含我的类中使用的所有类型的头。Ie以下面的MainWindow类为例,当在静态/动态库中编译时,使用库的人不必包括windows。h、Ie HWND、CRITICAL_SECTION、LRESULT等不必定义 我知道我可以将它分为两个类,一个是只包含公共接口的抽象类,另一个是包含需要windows.h的成员的隐藏实现类 这里的问题是visible类不能再自己创建,需要一个额外的创建函数(例如CreateMainWindow)。在这种情况下,这很好,因

如何“隐藏”类的某些部分,以便使用库的人不必包含我的类中使用的所有类型的头。Ie以下面的MainWindow类为例,当在静态/动态库中编译时,使用库的人不必包括windows。h、Ie HWND、CRITICAL_SECTION、LRESULT等不必定义

我知道我可以将它分为两个类,一个是只包含公共接口的抽象类,另一个是包含需要windows.h的成员的隐藏实现类

这里的问题是visible类不能再自己创建,需要一个额外的创建函数(例如CreateMainWindow)。在这种情况下,这很好,因为很可能只需要在堆上创建一个实例,但对于其他类则不需要

class MainWindow
{
    HWND hwnd;
    int width, height;
    std::string caption;
    bool started,exited;
    bool closeRequest;

    unsigned loopThread;
    CRITICAL_SECTION inputLock;

    Input *input;
public:
    static void init_type();
    Py::Object getattr(const char *name);

    MainWindow(int width, int height, std::string caption);
    ~MainWindow();

    bool CloseRequest(const Py::Tuple &args);
    bool CloseRequestReset(const Py::Tuple &args);

    HWND GetHwnd();

    int GetWidth();
    int GetHeight();

    Input* GetInput();
protected:
    unsigned static __stdcall loopThreadWrap(void *arg);
    unsigned LoopThreadMain();

    LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam);
    LRESULT static CALLBACK WndProcWrapper(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
};

这本书可能会给你一些想法:

大型C++软件设计< /P>


正如你在问题中提到的,使用抽象接口是你最好的选择。DLL应该具有用于创建/销毁具体类实例的工厂方法。我没有完全理解你关于这一缺点的观点。

你可以使用所谓的“柴郡猫”、“字母/信封”或“pimpl”技术隐藏类的一部分(对于同一种技术,它们都是不同的名称):


最好的方法可能是你在第二段中提到的抽象类(但我没能理解你的最后一句话,你(试图/未能)解释你的反论点是什么)。

不管怎样,你有两种选择:

  • 让库用户的编译器计算出数据所需的内存大小,然后编译器可以将其放在堆栈上
  • 或者为库用户分配堆上的数据,以便用户的编译器不需要知道数据有多大
  • 无论是通过pimpl还是MyAbstractObject*o=createMyObject()公开(2),都没有太大区别


    第三个选项(非常可怕的黑客行为,很有趣)是在你向用户公开的对象中创建一个大字节数组,然后使用“就地”新对象初始化该数组中的真实对象。请不要这样做。我要去用肥皂洗脑。

    正如前面所说的,你要用皮条客。我已经做到了,而且效果非常好。它对库的用户是完全透明的。

    注意,对于pimpl习惯用法,不需要特殊的工厂方法-ManWindow的构造函数(在本例中)应该负责构造ImplementationDetails对象。如果OP希望避免抽象类和工厂方法,那么客户机不需要处理这些。我认为他的意思是,由工厂方法创建的任何抽象类
    都不能被用户子类化,或者
    不能让该类的对象成为另一个类的成员,或者
    你不能把它们放在标准集装箱船上。我不确定Fire Lancer是否关心子类化,特别是考虑到类已经在DLL中编译的事实。您仍然可以拥有具有指向隐藏类实例的指针的成员的对象。
    class MainWindow
    {
    private:
        //opaque data
        class ImplementationDetails;
        ImplementationDetails* m_data;
    public:
        ... declare your public methods here ...
    }