tags:

views:

233

answers:

5

Hi folks,

On my company system, we use a class to represent beans. It is just a holder of information using boost::variant and some serialization/deserialization stuff. It works well, but we have a problem: it is not over an interface, and since we use modularization through dlls, building an interface for it is getting very complicated, since it is used in almost every part of our app, and sadly interfaces (abstract classes ) on c++ have to be accessed through pointers, witch makes almost impossible to refactor the entire system.

Our structure is:

dll A: interface definition through abstract class
dll B: interface implementation

there is a painless way to achieve that (maybe using templates, I don't know) or I should forget about making this work and simply link everything with dll B?

thanks

Edit: Here is my example.
this is on dll A
BeanProtocol is a holder of N dataprotocol itens, wich are acessed by a index.

class DataProtocol;

class UTILS_EXPORT BeanProtocol
{
public:
  virtual DataProtocol& get(const unsigned int  ) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void getFields(std::list<unsigned int>&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual DataProtocol& operator[](const unsigned int )
  {
    throw std::runtime_error("Not implemented");
  }

  virtual DataProtocol& operator[](const unsigned int ) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void fromString(const std::string&) 
  {
    throw std::runtime_error("Not implemented");
  }

  virtual std::string toString() const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual void fromBinary(const std::string&)
  {
    throw std::runtime_error("Not implemented");
  }

  virtual std::string toBinary() const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual BeanProtocol& operator=(const BeanProtocol&)
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator==(const BeanProtocol&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator!=(const BeanProtocol&) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool operator==(const char*) const
  {
    throw std::runtime_error("Not implemented");
  }

  virtual bool hasKey(unsigned int field) const
  {
    throw std::runtime_error("Not implemented");
  }
};

the other class (named GenericBean) implements it. This is the only way I've found to make this work, but now I want to turn it in a truly interface and remove the UTILS_EXPORT (which is an _declspec macro), and finally remove the forced linkage of B with A.

A: 

dll A: interface definition through abstract class

dll B: interface implementation

Can you explain what you mean by interface implementaion? In the ideal scenario, interfaces should really be no more than mere headers. Even if you have some default implementation, is it that big a burden to link them in?

What you describe is essentially a plug-in architecture. I am afraid there is no clean way of doing this via dlls.

Of course, if you are on Windows only, you could create COM classes (easy) or lookup the __declexport keyword.

And yes, I'd stay away from templates when using dlls -- they generally cause more trouble than they are worth.

dirkgently
-1, wrong. DLL A will create a vptr table and DLL B will create a second vptr table and the classes won't be compatible.
Joshua
@Joshua: I am not sure which part of my post you are referring to.
dirkgently
the part about "mere headers" causes vtable problems due to the way DLLs work.
Joshua
@Joshua: That part was meant to imply that do not use dlls.
dirkgently
A: 

If I recall you had to make the first listed constructor implemented in DLL A and do something with the exports table in the .DEF file to export that constructor and the VTABLE.

Joshua
A: 

honestly i don't really understand what are you trying to do, it seem like you have different interpretation on "interface" than most of us since you used a DLL to 'store" the base (interface/core/etc) and your so-called "interface" has "implementation" !

if your existing solution hasn't built around interface, it will require major recompiling if you introduce them, most likely no go from management point-of-view (unless your manager is tech-geek too).

YeenFei
A: 

Look, I may be completely off here, as I'm having a little trouble understanding your question. However, if I am correct, you want to remove the forced linkage between A and B.

You have the interface class, which has all pure virtual methods. Your app uses pointers of this type to communicate with the concrete objects.

Your DLL implements the abstract class, keeping all memory allocation and destruction within the DLL.

You create a factory function in your DLL, which returns a pointer of the abstract type, but does it actually instantiates a concrete object. The factory function needs to be exported in the DLL, nothing else.

Now you can link to the dll at runtime, call the factory function and instantiate objects.

Is that anything like what you had in mind?

Simon Parker
this is what I wanted to do, but the problem is just that on my system I'm not accessing it as pointers (since they aren't pure virtual) an I can't make it happen because the refactoring would be insane.
scooterman
A: 

I'm not exactly sure what you mean, but if the problem is that BeanProtocol is not a pointer, then couldn't you make it wrap a pointer to another class (say BeanPointerImpl) which you can then load from your DLL.

class BeanProtocol
{
  private BeanProtocolImpl m_impl;
  public:
  DataProtocol& get(const unsigned int index ) const
  {
    if(! m_impl)
    { 
       load_impl(get_appropriate_dll()) 
    }
    return m_impl->get(index);
  }

... and so on for all the other methods on BeanProtocol.

You can then implement your plugins as different subclasses of BeanProtocolImpl, export them from your DLL (DLL B in this case), and scrap DLL A.

In this example, I'm assuming that load_impl loads the DLL, calls the factory method to get an implementation of BeanProtocolImpl and stores that in m_impl, throwing an exception if it fails to load.

You would need to recompile the whole app, of course, but not refactor it.

Pat Wallace