Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.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++;单例设计:使用继承只调用一些实现的方法_C++_Singleton - Fatal编程技术网

C++ C++;单例设计:使用继承只调用一些实现的方法

C++ C++;单例设计:使用继承只调用一些实现的方法,c++,singleton,C++,Singleton,我有一个单件游戏,它是我游戏的主要引擎容器。 我有几个抽象类,让开发人员实现对特定对象所需的不同调用 我想做的是让我的单例对每个给定对象调用这些方法,但避免不必要的调用 示例以便您更好地理解: 假设一个对象同时需要Render()和Update()方法 现在,我想将该Sprite对象添加到我的单例引擎中,但我希望引擎只调用该对象继承的任何对象的每个循环(除了渲染和更新之外,还有其他事情,如检查输入等): 问题是,为了让它工作,我必须从一个基本接口继承所有接口,这样我就可以用创建的任何对象调用Ad

我有一个单件游戏,它是我游戏的主要引擎容器。
我有几个抽象类,让开发人员实现对特定对象所需的不同调用

我想做的是让我的单例对每个给定对象调用这些方法,但避免不必要的调用

示例以便您更好地理解:
假设一个对象同时需要Render()和Update()方法

现在,我想将该Sprite对象添加到我的单例引擎中,但我希望引擎只调用该对象继承的任何对象的每个循环(除了渲染和更新之外,还有其他事情,如检查输入等):

问题是,为了让它工作,我必须从一个基本接口继承所有接口,这样我就可以用创建的任何对象调用Add(),这样Add()方法就会接收一个基本接口对象

现在这里的问题是,基本接口必须至少抽象所有可以继承的方法,如Render()、Update()、CheckInput()、Etc(),并且每个循环我的singleton必须调用每个对象的所有可能性,即使sprite类的CheckInput()为空。
就像我的单身汉一样:

bool loop(){
  for every object saved in my container:
    CheckInput(); Update(); Render(); etc(); }
我的设计错了吗?有什么办法可以避免这种情况吗?
我希望你们明白我的意思,我的引擎处于非常先进的状态,我正在努力避免重写它


提前感谢。

如果您不需要调用chain CheckInput(),Update()。。。。在移动到下一个对象之前,在每个对象上调用该对象,并使对象注册它在单例上支持的操作

class Singleton {
  void Add(Base& object) {
    object.register(this);
  }

  void registerForInput(IInput& object) {
    addToInputList(object);
  }
}

class Some : public Base, public IInput {
  void register(Singleton *target) {
    target->registerForInput(*this);
  }
}
但是,如果在移动到下一个对象之前需要在一个对象上调用所有方法,请在该对象上创建一个方法,该方法将执行它支持的所有调用

class Singleton {
  void loop() {
    for all objects:
      object.performActions();
  }
}

class Some : public Base {
  void performActions() {
    checkForInput();
    render();
  }
}

如果不需要调用链CheckInput(),Update()。。。。在移动到下一个对象之前,在每个对象上调用该对象,并使对象注册它在单例上支持的操作

class Singleton {
  void Add(Base& object) {
    object.register(this);
  }

  void registerForInput(IInput& object) {
    addToInputList(object);
  }
}

class Some : public Base, public IInput {
  void register(Singleton *target) {
    target->registerForInput(*this);
  }
}
但是,如果在移动到下一个对象之前需要在一个对象上调用所有方法,请在该对象上创建一个方法,该方法将执行它支持的所有调用

class Singleton {
  void loop() {
    for all objects:
      object.performActions();
  }
}

class Some : public Base {
  void performActions() {
    checkForInput();
    render();
  }
}

如果让基接口定义太多纯虚函数,则每个派生类都必须定义它们。 我将在
IBase
中创建一个纯虚函数,让我们调用它
EngineCommunication
,在派生类中调用
CheckInput();更新();Render()等
(特定于类)
您的引擎将在循环中调用
EngineCommunication
,让具体的类决定要做什么。

如果您的基本接口定义了太多的纯虚函数,那么每个派生类都必须定义它们。 我将在
IBase
中创建一个纯虚函数,让我们调用它
EngineCommunication
,在派生类中调用
CheckInput();更新();Render()等
(特定于类)
您的引擎将在循环中调用
EngineCommunication
,让具体的类决定要做什么。

至少可以说,将所有方法从子类推到基类似乎很奇怪。为什么不尝试使用您想要调用的方法将每个对象动态地强制转换到接口上?如果强制转换返回null ptr,则跳过它:

bool loop()
{
   for every object saved in my conatiner:
       IRender* render = dynamic_cast<IRender*> (object_ptr);
       if (render != 0)
           render->Render ();

       // etc.
}
bool循环()
{
对于保存在my conatiner中的每个对象:
IRender*渲染=动态投影(对象投影);
如果(渲染!=0)
render->render();
//等等。
}

或者从子类中的单个方法调用所有操作-例如execute()。您可能需要为子类使用虚拟继承,以便只有一个IBase基类。

至少可以说,将所有方法从子类推送到基类似乎有些奇怪。为什么不尝试使用您想要调用的方法将每个对象动态地强制转换到接口上?如果强制转换返回null ptr,则跳过它:

bool loop()
{
   for every object saved in my conatiner:
       IRender* render = dynamic_cast<IRender*> (object_ptr);
       if (render != 0)
           render->Render ();

       // etc.
}
bool循环()
{
对于保存在my conatiner中的每个对象:
IRender*渲染=动态投影(对象投影);
如果(渲染!=0)
render->render();
//等等。
}

或者从子类中的单个方法调用所有操作-例如execute()。您可能需要为您的子类使用虚拟继承,以便只有一个IBase基。

如果您想编写类似于

bool loop()
{
    foreach IBase _base in _container do
    {
         _base->CheckInput();
         _base->Update();
         _base->Render();
         ...
    }
}
所有子类都必须有每个方法的实现。如果不希望最后一个类(即
Sprite
)实现所有方法,可以在子类中实现空方法,然后使用。但它会变得有点复杂。比如:

bool loop()
{
    foreach IBase _base in _container do
    {
         IChecker * _checker = dynamic_cast<IChecker *>(_base);
         if (_checker != 0)
             _checker->CheckInput();

         IUpdater * _updater = dynamic_cast<IUpdater *>(_base);
         if (_updater != 0)
             _updater->Update();

         IRender * _render = dynamic_cast<IRender *>(_base);
         if (_render != 0)
             _render->Render();
         ...
    }
}

class IBase
{
    virtual bool Render() = 0;
    virtual bool CheckInput() = 0;
    virtual bool Update() = 0;
    virtual bool Render() = 0;
    ...
}

class IRender : public virtual IBase
{
    virtual bool Render()
    {
         // do stuff
    }

    virtual bool CheckInput()
    {
        return false;
    }

    ...
}
bool循环()
{
foreach IBase在容器中的基
{
IChecker*_checker=动态施法(_base);
如果(_checker!=0)
_checker->CheckInput();
IUpdater*_updater=动态_cast(_base);
如果(_updater!=0)
_更新程序->更新();
IRender*_render=动态投射(_base);
如果(_render!=0)
_渲染->渲染();
...
}
}
IBase类
{
虚拟布尔渲染()=0;
虚拟布尔CheckInput()=0;
虚拟布尔更新()=0;
虚拟布尔渲染()=0;
...
}
IRender类:公共虚拟IBase
{
虚拟布尔渲染()
{
//做事
}
虚拟bool CheckInput()
{
返回false;
}
...
}

它很复杂,您可以毫无意义地重复代码。另外,我不知道动态播放的性能损失,但肯定有。我希望你能用这个想法来保存你的代码。

如果你想写这样的东西

bool loop()
{
    foreach IBase _base in _container do
    {
         _base->CheckInput();
         _base->Update();
         _base->Render();
         ...
    }
}
所有子类都必须有每个方法的实现。如果不希望最后一个类(即
Sprite
)实现所有方法,可以在子类中实现空方法,然后使用。日分
const TagList& tags = base->getTags();
for(TagList::const_iterator it = tags.begin(), end = tags.end(); it != end; ++it)
{
  switch(*it)
  {
  case IRender::Tag:
    base->render();
    break;
  case IUpdate::Tag;
    base->update();
    break;
  }
}
class Render
{
public:
  Render() : Base() { RenderSingleton::Add(this); }
  ~Render() { RenderSingleton::Remove(this); }
};

class RenderSingleton
{
public:
  static void Add(Render* i);
  static void Remove(Render* i);

  static void Render(....); // calls on each obj with specific render parameters
};
class ObjectListenerBase 
{
private:
    friend class ObjectManager;

    void onAdded(ScriptObject* obj) { doOnAddedBase(obj); }
    void onRemoved(ScriptObject* obj) { doOnRemovedBase(obj); }

    virtual void doOnAddedBase(ScriptObject* obj) = 0;
    virtual void doOnRemovedBase(ScriptObject* obj) = 0;
};

template<class T>
class ObjectListener : public ObjectListenerBase
{
protected:
    virtual void doOnAdded(T* obj) = 0;
    virtual void doOnRemoved(T* obj) = 0;

private:
    void doOnAddedBase(ScriptObject* obj) { if (T* o = dynamic_cast<T*>(obj)) { doOnAdded(o); } }
    void doOnRemovedBase(ScriptObject* obj) { if (T* o = dynamic_cast<T*>(obj)) { doOnRemoved(o); } }
};

//// how add object might look like

void ObjectManager::addObject(const std::string& object_name, ScriptObjectPtr s_object)
{
    ....

    for_each(m_listeners, boost::bind(&ObjectListenerBase::onAdded, _1, s_object.get()));
}

//// how a listener might look like
class AIEngine : public ObjectListener<IThinker>
{
public:
    AIEngine() { ObjectManager::the().addListener(this); }

    void think() { for_each(m_ais, boost::bind(&IThinker::think, _1, ...));

protected:
    virtual void doOnAdded(IThinker* obj) { m_ais.push_back(obj) }
    virtual void doOnRemoved(IThinker* obj) { m_ais.erase(obj); }

private:
    ptr_set<IThinker> m_ais;
}