C++ 继承 class 并将修改后的参数发送给父级的构造函数
C++ Inherit class with sending modified parameters to parent's constructor
我想创建 class 继承,我的新 class 创建父对象 class 的对象,设置一些默认参数(指向其他对象的指针)。
一开始我有:
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);
我想要这样的东西:
colWorld = new myBtCollisionWorld(dbgdraw);
我尝试了很多东西并发明了一个技巧
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;
};
这背后的想法是首先调用 "initializer" class 构造函数并覆盖 btCollisionWorld class.
的变量
突然间它起作用了。
我知道这似乎是试图开始毫无意义的讨论,但我不擅长 C++,而且在谷歌搜索时确实没有找到类似的东西;所以我很好奇是否存在任何可能的陷阱或其他实现方法。
好像太复杂了。从设置一些硬编码值的 class 继承看起来不太好。如果您真的希望派生的 class 在逻辑上是分开的(基于 init 参数),最好将其模板化。它将允许您根据不同的初始化参数创建更多这样的 classes。
这是我的理解(如果我错了告诉我,我会删除答案):
你的设计好像很复杂。起初我以为你没有利用继承权。但后来我意识到问题应该更复杂。这是我的理解:
你有一个基础 class,它的构造函数依赖于它的环境(例如一些外部变量)。我尝试一个更简单的例子:
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.
...
}
...
};
然后您想要派生一个 class,其中的构造函数参数应该影响基础 class 的环境。
class DWorld : public World {
public:
DWorld(Dispatcher* d) : World() {
dispatcher = d; // too late: the base is already created !!!
...
}
...
};
此逻辑在标准中定义:
- 基础 class 部分总是在派生 class
之前构造
- 首先执行基础初始化器(可能初始化基础,如果不是默认基础构造函数)然后是其他成员,然后才执行构造函数的主体指令。
简而言之:在初始化基础之前,DWorld 无法做任何事情!
你的技巧是这样的:
所以你的技巧是使用多重继承。很聪明!
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
}
...
};
这不是巧合:这在 C++ 标准中也有非常精确的定义:在多重继承的情况下,基初始化器按照您在继承语句中定义它们的顺序运行。所以在这里,首先 Helper
然后 World
。
然而,您随后必须处理多重继承,这可能很困难,尤其是当继承树的多个不同层需要同一个助手时。
再来一招:
不幸的是,它只能在一种情况下工作:您的基本构造函数必须至少采用一个参数。
假设我有一个构造函数 World(int a
)。在这种情况下,我可以使用辅助函数来避免多重继承:
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 !
};
这是因为必须首先评估函数才能调用 World
构造函数这一事实。
带有 lambda 函数的变体,虽然可读性较差,但允许您捕获作用域中的任何变量并以最合适的方式使用它们:
DWorld(Dispatcher* d) : World([&]()->int {dispatcher = d; return 0; }()) {...}
结论
这里有一些工具可以解决您的紧迫问题。然而诡计终归是诡计。这是一种解决方法。最好的解决方案是重新设计基础 class。
我想创建 class 继承,我的新 class 创建父对象 class 的对象,设置一些默认参数(指向其他对象的指针)。
一开始我有:
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);
我想要这样的东西:
colWorld = new myBtCollisionWorld(dbgdraw);
我尝试了很多东西并发明了一个技巧
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;
};
这背后的想法是首先调用 "initializer" class 构造函数并覆盖 btCollisionWorld class.
的变量突然间它起作用了。
我知道这似乎是试图开始毫无意义的讨论,但我不擅长 C++,而且在谷歌搜索时确实没有找到类似的东西;所以我很好奇是否存在任何可能的陷阱或其他实现方法。
好像太复杂了。从设置一些硬编码值的 class 继承看起来不太好。如果您真的希望派生的 class 在逻辑上是分开的(基于 init 参数),最好将其模板化。它将允许您根据不同的初始化参数创建更多这样的 classes。
这是我的理解(如果我错了告诉我,我会删除答案):
你的设计好像很复杂。起初我以为你没有利用继承权。但后来我意识到问题应该更复杂。这是我的理解:
你有一个基础 class,它的构造函数依赖于它的环境(例如一些外部变量)。我尝试一个更简单的例子:
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.
...
}
...
};
然后您想要派生一个 class,其中的构造函数参数应该影响基础 class 的环境。
class DWorld : public World {
public:
DWorld(Dispatcher* d) : World() {
dispatcher = d; // too late: the base is already created !!!
...
}
...
};
此逻辑在标准中定义:
- 基础 class 部分总是在派生 class 之前构造
- 首先执行基础初始化器(可能初始化基础,如果不是默认基础构造函数)然后是其他成员,然后才执行构造函数的主体指令。
简而言之:在初始化基础之前,DWorld 无法做任何事情!
你的技巧是这样的:
所以你的技巧是使用多重继承。很聪明!
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
}
...
};
这不是巧合:这在 C++ 标准中也有非常精确的定义:在多重继承的情况下,基初始化器按照您在继承语句中定义它们的顺序运行。所以在这里,首先 Helper
然后 World
。
然而,您随后必须处理多重继承,这可能很困难,尤其是当继承树的多个不同层需要同一个助手时。
再来一招:
不幸的是,它只能在一种情况下工作:您的基本构造函数必须至少采用一个参数。
假设我有一个构造函数 World(int a
)。在这种情况下,我可以使用辅助函数来避免多重继承:
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 !
};
这是因为必须首先评估函数才能调用 World
构造函数这一事实。
带有 lambda 函数的变体,虽然可读性较差,但允许您捕获作用域中的任何变量并以最合适的方式使用它们:
DWorld(Dispatcher* d) : World([&]()->int {dispatcher = d; return 0; }()) {...}
结论
这里有一些工具可以解决您的紧迫问题。然而诡计终归是诡计。这是一种解决方法。最好的解决方案是重新设计基础 class。