Sign in to follow this  
mikeman

Problem when wrapping libraries

Recommended Posts

For this example, I will use the library Cal3d, but it would be the same for pretty much any other library. We have 2 classes, CalCoreModel and CalModel. These are used like: CalCoreModel coreModel("core"); CalModel model(&coreModel); Now, in my engine I want to "wrap" these classes, so I can add some "smart" functionality I want,and maybe make my code API-indepedent(so I could substitute Cal3D when another lib in the future). So it becomes:
class MyCoreModel
{
private:
  CalCoreModel calCoreModel;
public:
  MyCoreModel(std::string name):calCoreModel(name){}
  void LoadCoreAnim(std::string name)
  {
    calCoreModel.loadCoreAnimation(name);
  }
};

class MyModel
{
private:
  CalModel calModel;
public:
  MyModel(MyCoreModel& core):calModel(???){}//PROBLEM
};

As you can see, in order to create the CalModel, I need to take a look at the "guts" of MyCoreModel and get the CalCoreModel private member. How do I do this? If I add a GetCalCoreModel() member function in MyCoreModel, then I have exposed some of the implementation details into the public interface. The "friend" approach is usually a codesmell. Is there any other way this can be succeded sanely?

Share this post


Link to post
Share on other sites
One approach, if you have to use the constructor to construct a CalModel object (there should be some other Load function though)

class MyCoreModel
{
private:
CalCoreModel calCoreModel;

public:
// In the header file, you can forward declare class CalModel;
// You will include the header file that declares CalModel in the .cpp
// to reduce header dependencies.
void ConstructModel(CalModel * model)
{
model = new CalModel(&calCoreModel);
}
};

class MyModel
{
private:
CalModel * calModel;

public:
MyModel(MyCoreModel& core) : calModel(0)
{
core.ConstructModel(calModel); // if new throws, calModel should still be 0
}
~MyModel
{
delete calModel;
}
};


That would be one clean way to go about it. Another way is similar to that, but rather than use the constructor of CalModel, you would find some other function that accomplishes the same thing. That way, you don't have to use pointers and memory allocations/cleanup.

Share this post


Link to post
Share on other sites
One option is to move to abstract base classes for your personal interfaces and have implementations perform checked_casts where necessary.

// interface:
struct ICoreModel {
virtual void LoadCoreAnim(std::string name) = 0;
virtual ~ICoreModel() = 0;
};

struct IModel {
virtual ~IModel() = 0;
};

std::auto_ptr<ICoreModel> create_cal3d_core_model(std::string name);
std::auto_ptr<IModel> create_cal3d_model(ICoreModel & core);

// implementation:
struct Cal3DCoreModel : ICoreModel {
CalCoreModel calCoreModel;

Cal3DCoreModel(std::string name) : calCoreModel(name) {}
virtual void LoadCoreAnim(std::string name) { calCoreModel.loadCoreAnimation(name); }
virtual Cal3DCoreModel() {}
};

struct Cal3DModel : IModel {
CalModel calModel;

Cal3DModel(ICoreModel & core) : calModel(checked_cast<Cal3DCoreModel &>(core).calCoreModel) {}
};

std::auto_ptr<ICoreModel> create_cal3d_core_model(std::string name) {
std::auto_ptr<ICoreModel> temp(new Cal3DCoreModel(name));
return temp;
}

std::auto_ptr<IModel> create_cal3d_model(ICoreModel & core) {
std::auto_ptr< IModel > temp(core);
return temp;
}

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this