I want to create class inheritance, where my new class creates object of parent class, setting some default parameters (which are pointers to other objects).
At the beginning I had:
btDefaultCollisionConfiguration* collisionConfiguration =
new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
btVector3 worldAabbMin(-1000,-1000,-1000);
btVector3 worldAabbMax(1000,1000,1000);
btAxisSweep3* broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax);
colWorld = new btCollisionWorld(dispatcher,broadphase,collisionConfiguration);
colWorld->setDebugDrawer(dbgdraw);
I want to have something like:
colWorld = new myBtCollisionWorld(dbgdraw);
I tried many things and invented a trick
btVector3 worldAabbMin;
btVector3 worldAabbMax;
class BtOgreCollisionWorld_initializer { //A trick: we need one more constructor to
// initialize default variables; Then we will pass them to btCollisionWorld
// as it stands next in inheritance list
public:
BtOgreCollisionWorld_initializer(btCollisionDispatcher *&dispatcher,
btAxisSweep3 *&broadphase,
btDefaultCollisionConfiguration *&collisionConfiguration)
{
if (!worldAabbMin) worldAabbMin = btVector3(-1000,-1000,-1000);
if (!worldAabbMax) worldAabbMax = btVector3(1000,1000,1000);
if (!collisionConfiguration)
collisionConfiguration = new btDefaultCollisionConfiguration();
if (!dispatcher)
dispatcher = new btCollisionDispatcher(collisionConfiguration);
if (!broadphase) broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax);
};
};
class BtOgreCollisionWorld: public BtOgreCollisionWorld_initializer,
public btCollisionWorld {
public:
//using btCollisionWorld::btCollisionWorld;
BtOgreCollisionWorld(BtOgre::DebugDrawer *dbgdraw,
btCollisionDispatcher* dispatcher = 0, btAxisSweep3* broadphase = 0,
btDefaultCollisionConfiguration* collisionConfiguration = 0)
: BtOgreCollisionWorld_initializer(dispatcher, broadphase,
collisionConfiguration),
btCollisionWorld(dispatcher, broadphase, collisionConfiguration)
{
/*copying variables above*/
this->setDebugDrawer(dbgdraw);
};
protected:
btDefaultCollisionConfiguration* collisionConfiguration;
btCollisionDispatcher* dispatcher;
btVector3 worldAabbMin;
btVector3 worldAabbMax;
btAxisSweep3* broadphase;
};
The idea behind this was that "initializer" class constructor is called first and overwrites the variables for btCollisionWorld class.
And suddenly it worked.
I understand that it may seem as an attempt to start a pointless discussion, but I'm not skilled at c++ and really haven't found anything like that while googled for it; so I'm just curious if there are any possible pitfalls or other ways to implement this.
Here is what I understand (tell me if I'm wrong, I'll delete the answer):
Your design seems very complicated. At first I thought that you didn't make use of the inheritance. But then I realised that the problem should be more complex. Here is what I understood:
You have a base class whith a constructor that is dependent on its environment (for example some external variables). I try with a simpler example:
Dispatcher* dispatcher = new Dispatcher(xyz); // global parameter
class World {
private:
Dispatcher *my_dispatcher; // some private that you can't change later on
public:
World() {
my_dispatcher = dispatcher; // take over the global.
...
}
...
};
You then want to derive a class, with a constructor parameter that should affect the environment for the base class.
class DWorld : public World {
public:
DWorld(Dispatcher* d) : World() {
dispatcher = d; // too late: the base is already created !!!
...
}
...
};
This logic is defined in the standard:
- the base class part is always constructed before the derived class
- first the base initializers are executed (potentially initializing base, if not it's default base constructor) then the other members, and only then the constructor's body instructions.
In short: there is no way the DWorld could do something before initializing the base !
Here is how your trick works:
So your trick is to use multiple inheritance. It's clever !
class Helper {
public:
Helper (Dispatcher* d) {
dispatcher = d;
// do whatever you want to do before World base is intialized
}
};
class DWorld : public Helper, public World {
public:
DWorld(Dispatcher* d) : Helper(d), World() {
... // everything is fine
}
...
};
This is not coincidence: this is also defined very precisely in the C++ standard: in case of multiple inheritance, the base initializers operate in the order in which you defined them in the inheritance statement. So here, first Helper
then World
.
However you then have to deal with multiple inheritance, which can be difficult, especially if the same helper is needed at several different layers of the inheritance tree.
Now another trick:
Unfortunately, it works under one condition: your base constructor must take at least one parameter.
Suppose I had a constructor World(int a
). In this case I could a helper function avoiding multiple inheritance:
int helper(Dispatcher*d, int a) {
dispatcher = d;
return a;
}
class DWorld : public World { // single inheritance
public:
DWorld(Dispatcher* d) : World(helper(0)) { } // but function pipeline !
};
This works using the fact that the function must be evaluated first in order to call the World
constructor.
The variant with lambda functions, although less readable, permits you even to capture any variables in scope and use them as best fits:
DWorld(Dispatcher* d) : World([&]()->int {dispatcher = d; return 0; }()) {...}
Conclusions
You have here some tools to solve your immedite problem. However a trick remains a trick. It's a workaround. he best solution would be to redesign the base class.
It seems too overcomplicated. Inheriting from a class which sets some hard-coded values doesn't looks great. If you really want the derived class to be logically separate (based on the init parameters) it would better to template it. It will allow you to create more such classes based on different initialization params.