Jason S
Jason S

Reputation: 189686

C++: decoupling of interface / implementation w/o using virtual functions?

I've been spoiled using Java in the last few months! I have a C++ project where I would like to decouple a class interface (.h file) from its implementation details. But the class's member fields have to be in its declaration, and it seems like I have this unavoidable dependency linking if I want to tweak the class's member fields.

I know one way to do this is using polymorphism + class inheritance (make the interface a base class, make the implementation a derived class), but if I remember right, that requires virtual functions, which are something I would like to avoid -- this is on a DSP and it's advantageous not to get too "C++-y" with things.

any suggestions?

Upvotes: 4

Views: 3057

Answers (4)

rmn
rmn

Reputation: 2426

Use the pimpl idiom. Read here: http://www.devx.com/cplus/Article/28105/0/page/3

It will help decoupling the implementation from the interface and will reduce (to a minimum) all compilation dependencies. You can even avoid virtual functions.

Upvotes: 1

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84169

Here's an old idea :) - opaque data type plus a set of functions, i.e. "there and back [to C] again":


// oi.hpp
namespace oi // old idea
{
    struct opaque; // forward declaration

    void init( opaque& ); // ctor
    void fini( opaque& ); // dtor

    int get_foo( const opaque& ); // getter
    void set_foo( opaque&, int ); // setter
}
// oi.cpp
namespace oi
{
    struct opaque // definition
    {
        int foo_; // data members
        // ...
    };

    // function definitions
}

The runtime cost of accessing the structure via reference is probably the same as with pimpl, so this is probably an inferior solution given some important idioms like RAII cannot be used.

Upvotes: 0

Omnifarious
Omnifarious

Reputation: 56048

You know, I thought about this and your objection to PIMPL for a bit.

I have an ugly hack I use sometimes for cases like this, where I resent paying the indirection penalty. Though usually my complaint is with calling new, and not with the pointer dereference. I present my ugly hack thusly:

//  IHaveOpaqueData.h

class IHaveOpaqueData {
 public:
    // To make sure there are no alignment problems, maybe ::std::uin64_t
    typedef maximally_aligned_type_t internal_data_t[32];  // Some size I hope is big enough

    void iCanHazMemberFunction();
    // ...
 private:
    internal_data_t data;
};

//  IHaveOpaqueData.cpp
#include <boost/static_assert.hpp>

namespace { // Hide it in an anonymous namespace
struct RealData {
    int icanhazmembervariable_;
    double icanhazdoublevariable_;
};
BOOST_STATIC_ASSERT(sizeof(RealData) < sizeof(IHaveOpaqueData::internal_data_t);
}

void IHaveOpaqueData::iCanHazMemberFunction()
{
    // Use a reference to help the optimize make the right decision
    RealData &datathis = *(reinterpret_cast<RealData *>(&(this->data)));
    datathis.icanhazmembervariable_ = datathis.icanhazdoublevariable_;
}

Yes, this is ugly. BOOST_STATIC_ASSERT (or if you have a C++[01]x compiler the static_assert keyword) helps make it not be a total disaster. There may be a clever way to use unions to mitigate some of the twitchiness I have over alignment issues as well.

Upvotes: 2

anon
anon

Reputation:

You want the PIMPL idiom.

Upvotes: 12

Related Questions