开发者

Hide class type in header

开发者 https://www.devze.com 2023-01-12 02:36 出处:网络
I\'m not sure if this is even possible, but here goes: I have a library whose interface is, at best, complex. Unfortunately, not only is it a 3rd-party library (and far too big to rewrite), I\'m usin

I'm not sure if this is even possible, but here goes:

I have a library whose interface is, at best, complex. Unfortunately, not only is it a 3rd-party library (and far too big to rewrite), I'm using a few other libraries that are dependent on it. So that interface has to stay how it is.

To solve that, I'm trying to essentially wrap the interface and bundle all the dependencies' interfaces into fewer, more logical classes. That part is going fine and works great. Most of the wrapper classes hold a pointer to an object of one of the original classes. Like so:

class Node
{
public:
    String GetName()
    {
        return this->llNode->getNodeName();
    }

private:
    OverlyComplicatedNodeClass * llNode; // low-level node
};

My only problem is the secondary point of this. Beside simplifying the interface, I'd like to remove the requirement for linking against the original headers/libraries.

That's the first difficulty. How can I wrap the classes in such a way that there's no need to include the original headers? The wrapper will be built as a shared-library (dll/so), if that makes it simpler.

The original classes are po开发者_高级运维inters and not used in any exported functions (although they are used in a few constructors).

I've toyed with a few ideas, including preprocessor stuff like:

#ifdef ACCESSLOWLEVEL
#    define LLPtr(n) n *
#else
#    define LLPtr(n) void *
#endif

Which is ugly, at best. It does what I need basically, but I'd rather a real solution that that kind of mess.

Some kind of pointer-type magic works, until I ran into a few functions that use shared pointers (some kind of custom SharedPtr<> class providing reference count) and worse yet, a few class-specific shared pointers derived from the basic SharedPtr class (NodePtr, for example).

Is it at all possible to wrap the original library in such a way as to require only my headers to be included in order to link to my dynamic library? No need to link to the original library or call functions from it, just mine. Only problem I'm running into are the types/classes that are used.

The question might not be terribly clear. I can try to clean it up and add more code samples if it helps. I'm not really worried about any performance overhead or anything of this method, just trying to make it work first (premature optimization and all that).


Use the Pimpl (pointer to implementation) idiom. As described, OverlyComplicatedNodeClass is an implementation detail as far as the users of your library are concerned. They should not have to know the structure of this class, or even it's name.

When you use the Pimpl idiom, you replace the OverlyComplicatedNodeClass pointer in your class with a pointer to void. Only you the library writer needs to know that the void* is actually a OverlyComplicatedNodeClass*. So your class declaration becomes:

class Node
{
public:
    String GetName();

private:
    void * impl; 
};

In your library's implementation, initialize impl with a pointer to the class that does the real work:

my_lib.cpp

Node::Node()
: impl(new OverlyComplicatedNodeClass)
{
// ...
};

...and users of your library need never know that OverlyComplicatedNodeClass exists.

There's one potential drawback to this approach. All the code which uses the impl class must be implemented in your library. None if it can be inline. Whether this is a drawback depends very much on your application, so judge for yourself.

In the case of your class, you did have GetName()'s implementation in the header. That must be moved to the library, as with all other code that uses the impl pointer.


Essentially, you need a separate set of headers for each use. One that you use to build your DLL and one with only the exported interfaces, and no mention at all of the encapsulated objects. Your example would look like:

class Node
{
public:
    String GetName();
};

You can use preprocessor statements to get both versions in the same physical file if you don't mind the mess.

0

精彩评论

暂无评论...
验证码 换一张
取 消