tags:

views:

302

answers:

5

How can I "hide" parts of a class so that whoever is using the libary does not have to include headers for all the types used in my class. Ie take the MainWindow class below, ho can I have it so when compiled in a static/dynamic libary, whoever is useing the libary does NOT have to include windows.h, ie HWND, CRITICAL_SECTION, LRESULT, etc do not have to be defined.

I know I could split it into two classes, an abstract class with just the public interface, and an implementation class which is hidden that contains the members that require windows.h.

The problem here is that the visible class can no longer be created itsself, and an additional create function (eg CreateMainWindow) is required. That is fine in this case since it is most likly that just a single instance created on the heap is wanted but for other classes this is not.

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);
};
A: 

This book may give you some ideas:

http://www.amazon.com/Large-Scale-Software-Addison-Wesley-Professional-Computing/dp/0201633620

Large-Scale C++ Software Design

by John Lakos

Otávio Décio
+4  A: 

As you mentioned in your question, using an abstract interface is your best option. Your DLL should have factory methods for creating/destroying instances of your concrete class. I didn't quite get your point about the downside of this.

Ates Goral
I think he means that any abstract class created by a factory method <br> can't be subclassed by the user, or <br> that you can't have objects of that class that are members of another class, or<br> you can't put them in standard containers
Die in Sente
Hmmm. I'm not sure if Fire Lancer was concerned with subclassing at all, especially given the fact that the class is already compiled inside a DLL. You could still have objects that have members that are pointers to the instances of the hidden class.
Ates Goral
+7  A: 

You can hide parts of a class using the so-called "cheshire cat", "letter/envelope", or "pimpl" technique (which are, all, different names for the same technique):

class MainWindow
{
private:
    //opaque data
    class ImplementationDetails;
    ImplementationDetails* m_data;
public:
    ... declare your public methods here ...
}

The best way is probably the abstract class mentioned in your 2nd paragraph (however I failed to understand your last sentence, in which you (tried/failed to) explain what your counter-argument to that is).

ChrisW
Note that with the pimpl idiom, a special factory method is not required - the constructor for ManWindow (in this case) should take care of constructing an ImplementationDetails object. The client need not deal with abstract classes and factory methods if that's what the OP wants to avoid.
Michael Burr
+1  A: 

One way or the other, you have two options:

  1. let the library user's compiler figure out the memory size needed for your data - then the compiler can place it on stack
  2. or allocate the data on the heap for the library user so that the user's compiler does not need to know how big the data are.

Whether you expose (2) via pimpl or MyAbstractObject *o = createMyObject() is not much different.

A third option (a hack so terrible, it's funny) creates a large byte array in the object you expose to the user, and you initialize your real objects in that array using "in-place" new. Please don't do this. I'll go and wash my brains with soap.

Arkadiy
A: 

As has been said before, you want to use a pimpl. I've done it and it works really well. It's totally transparent to the user of your library.

Rob K