Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;继承类,并将修改后的参数发送到父级';s构造函数_C++_Class_Pointers_Inheritance_Constructor - Fatal编程技术网

C++ C++;继承类,并将修改后的参数发送到父级';s构造函数

C++ C++;继承类,并将修改后的参数发送到父级';s构造函数,c++,class,pointers,inheritance,constructor,C++,Class,Pointers,Inheritance,Constructor,我想创建类继承,在这里我的新类创建父类的对象,设置一些默认参数(它们是指向其他对象的指针) 一开始我有: btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration(); btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration); btVec

我想创建类继承,在这里我的新类创建父类的对象,设置一些默认参数(它们是指向其他对象的指针)

一开始我有:

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;
};
这背后的想法是首先调用“初始值设定项”类构造函数,并覆盖btCollisionWorld类的变量

突然,它起了作用


我知道这似乎是一个尝试,开始一个毫无意义的讨论,但我不熟练的C++,并没有发现任何类似的谷歌,因为它;因此,我只是好奇是否有任何可能的陷阱或其他实现方法。

它似乎过于复杂。从设置了一些硬编码值的类继承看起来不太好。如果您确实希望派生类在逻辑上是独立的(基于init参数),那么最好将其模板化。它将允许您基于不同的初始化参数创建更多这样的类

它似乎过于复杂了。从设置了一些硬编码值的类继承看起来不太好。如果您确实希望派生类在逻辑上是独立的(基于init参数),那么最好将其模板化。它将允许您基于不同的初始化参数创建更多这样的类

它似乎过于复杂了。从设置了一些硬编码值的类继承看起来不太好。如果您确实希望派生类在逻辑上是独立的(基于init参数),那么最好将其模板化。它将允许您基于不同的初始化参数创建更多这样的类

它似乎过于复杂了。从设置了一些硬编码值的类继承看起来不太好。如果您确实希望派生类在逻辑上是独立的(基于init参数),那么最好将其模板化。它将允许您基于不同的初始化参数创建更多这样的类

以下是我的理解(如果我错了,请告诉我,我将删除答案)

你的设计似乎很复杂。起初我以为你没有利用遗产。但后来我意识到问题应该更复杂。以下是我的理解:

您有一个基类,其构造函数依赖于它的环境(例如一些外部变量)。我尝试用一个更简单的例子:

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 DWorld : public World {
public: 
    DWorld(Dispatcher* d) : World() { 
        dispatcher = d;  // too late:  the base is already created !!!    
        ...
    }
    ...
};
该逻辑在标准中定义:

  • 基类部分总是在派生类之前构造
  • 首先执行基初始值设定项(如果不是默认的基构造函数,则可能初始化基),然后执行其他成员,然后才执行构造函数的主体指令
简言之:在初始化基础之前,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

但是,您必须处理多重继承,这可能会很困难,尤其是在继承树的几个不同层上需要相同的助手时

现在还有一个窍门:

不幸的是,它在一个条件下工作:基本构造函数必须至少接受一个参数

假设我有一个构造函数世界(
inta
)。在这种情况下,我可以使用一个helper函数来避免多重继承:

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;  }()) {...}
结论


这里有一些工具可以解决你的急迫问题。然而,诡计仍然是诡计。这是一个解决办法。他认为最好的解决方案是重新设计基类

以下是我的理解(如果我错了,请告诉我,我将删除答案)

你的设计似乎很复杂。起初我以为你没有利用遗产。但后来我意识到问题应该更复杂。以下是我的理解:

您有一个基类,其构造函数依赖于它的环境(例如一些外部变量)。我尝试用一个更简单的例子:

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 DWorld : public World {
public: 
    DWorld(Dispatcher* d) : World() { 
        dispatcher = d;  // too late:  the base is already created !!!    
        ...
    }
    ...
};
该逻辑在标准中定义:

  • 基类部分总是在派生类之前构造
  • 首先执行基初始值设定项(如果不是默认的基构造函数,则可能初始化基),然后执行其他成员,然后才执行构造函数的主体指令
简言之:在初始化基础之前,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

然而,您必须处理多重继承,这可能是