I am currently writing some sort of library or framework. I have two classes, say CFoo and CBar. Their properties can be described as follows:
1. Users of the framework are meant to derive their own classes from these two. The user has to implement some virtual methods and is given some helper methods (at the moment only one getter) by the classes.
2. Both classes have a lot of common functionality, so there is a common base class CBase. The interface of this base class is strictly internal and can change without any notification and should not be exposed to the frameworks user.
3. There are some internal classes, which use both CBar and CFoo and need to know about the inheritance structure.
I'm wondering how to implement this. My first approach was like this, using private inheritance:
class CBase
{
public:
virtualvoid doSomething() = 0;
// internal interface used by CFoo and CBar
};
class CFoo : private CBase
{
public:
virtualvoid doSomethingElse() = 0;
// Public interface for the user
private:
void doSomething() { ... };
};
class CBar : private CBase
{
public:
virtualvoid doSomethingElse() = 0;
// Public interface for the user
private:
void doSomething() { ... };
};
This approach has the disadvantage, that any (framework internal) class needing to know about the inheritance relationship needs to be a friend of (potentially) both CBar and CFoo.
Is there any elegant way to achieve the structure I want to have? Maybe over using some sort of aggregation or putting another inheritance layer above my classes?
Out of curiosity, may I ask you to explain what the classes are actually modelling? The names Foo and Bar are less than descriptive.
My initial thought is that perhaps you could inherit an interface from a base class publicly and separate the common implementation such that it can be inherited privately. Do you have to hide the fact that CFoo and CBar have a common base class from the external users?
its meant to become a framework for implementing large object data models, which are lazy updated.
So you have a (rather large) graph of objects, and modifications to this graph are done by Events. Furthermore, all this is timed, using a discrete time model, and the execution time of an event may depend on the current state of some objects.
In the terminus from the first post, CBar models an Object and CFoo models an event. The common base class is modeling an updatable, as both Objects and Events need to be updated, and the functionality for doing so is nearly the same.
I don't have to hide anything from external users, but i would rather do so - at least the user should not "know" about the methods the common base class provides for internal use. Of course, he may know about them, but iwant to strongly discourage the use of them to prevent reliance on the functionality of these methods.
By your suggestion, did you mean something like the following?
1. Rename CFoo and CBar to CFooImpl and CBarImpl, respectivly.
2. Inherit new classes CFoo and CBar privately from the implementation classes.
3. Implement simple (inlined) "Call through"-Methods to the real implementations.
That would indeed be a reasonable way to solve the problem, my only concern is efficiency... but when i think about it, there should be no noticable performance impact. At least when the compiler optimization hits in and inlines ever call through method.
//forward declaration
class CBase;
class CFoo
{
private:
CBase base_delegate;
// Private class implementation
// (change infreqently)
void doMagic();
protected:
// Protected interface for user use
// (never or rarely change)
virtualvoid doSometingElse();
public:
// Public interface for the user
// (never change!)
void doSomethingMagic(){
doMagic();
doSometingElse();
userFunction();
};
virtualvoid userFunction() = 0;
};
class CBar
{
private:
CBase base_delegate;
public:
void doNonMagic();
};
void CFoo::doMagic();
{
base_delegate.doBlackArt();
}
void CBar::doNonMagic()
{
base_delegate.doBlackArt();
}
// Hide in CBase.cpp:
class CBase : public CBaseBase, private CBaseInterface // any form of inheritance or without
{
// internal interface used by CFoo and CBar
// can change without any notification
// any implemenation and interface as you wish
};
if i use delegation in this way, other internal classes (which use CBases interface) do not know about the inheritance relationship, as i only include Foo.h and Bar.h for them... so that does not solve the problem (Point 3). Internal classes might be needing to convert a CBase to a CFoo or CBar.
This is bad idea(if you mean downcast), who taught you that?
If you really want to convert CBase to CFoo or CBar it is not required derivative from CBase.
Maybe there is no need for class casting ever? Events and objects are different things enough.
And what you mean by
You could move the common stuff to a separate class hierarchy and add a getter into your original hierarchy.
1 2 3 4 5 6 7 8 9 10 11 12
// internal usage only. Defined somewhere not accessible to normal users
class CInternHelperBase;
class CFoo
{
public:
// can be called by everyone, but only internal classes know the complete type.
CInternHelperBase* getHelper();
virtualvoid doSomethingElse() = 0;
...
};
Implementation of CFoo:
1 2 3 4 5 6 7 8 9 10 11 12
#include "CInternalHelperBase.h" // header is in project-only folder and not shipped to your users
class CFooHelper : public CInternalHelperBase
{
public:
virtualvoid doSomething() { ... }
};
CInternHelperBase* CFoo::getHelper()
{
returnnew CFooHelper;
}
You should consider using std::shared_ptr, boost::shared_ptr, std::unique_ptr or std::auto_ptr for the CFooHelper for less hazzle with memory management.
@boolivar: With "need to know about the inheritance structure" i meant, that i want some internal classes to have methods like void method(CBase& toDoSomethingWith),
and i want to call these methods with instances of CFoo and CBar. To be able to do this, the caller needs to know that CFoo is inherits from CBase, otherwise it is a compile time error (as it should be). Downcasts (or something similar) are needed sometimes to improve efficiency, but i agree, its nothing to be used to often.
For the moment i have solved the problem as as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
class CBase
{
public:
virtualvoid doSomething() = 0;
};
class CFooImpl : public CBase
{
public:
virtualvoid doSomething() { ... }
virtualvoid doSomethingElse() = 0;
};
class CFoo : private CFooImpl
{
public:
virtualvoid doSomethingElse() = 0;
};
Internally i work only with CFooImpl, except in interfaces to the end user.
i was otherwise occupied the past week, but better a later answer than none.
Thanks for the suggestions. The first solution (see post #3) failed, when i tried to serialize the whole thing with boost::serialization, as boost::serialization can't cope with private inheritance.
Now i have implemented it in a similar way as boolivar suggestet in his last post, but as the base class is not only used to delegate calls, but there are also incoming calls of virtual methods from it, i did the following:
Now no one using CFoo "knows" about the inheritance, but everything works out fine. It also has the advantage of working correctly with my memory management approach :-)