简体   繁体   中英

How to manage encapsulation by preserving performance

I'm trying to figure out the best solution to the following problem:

I have a library (which is not modifiable directly) that manages the graphics of a game. I have a Entity class which is the logical entity of a displayable entity which is paired by a Sprite instance.

The graphics library already contains support to manage a collection of sprites so I'd like to use it even for the logic without letting the logic know about the graphical engine at all (I don't want to need to include the header), for all the purposes that are related to iterating over the entities (which are many are require many updates per second).

To obtain this solution while preserving encapsulation I figured a solution similar to this one (I oversimplified it):

gfx_engine.h (not modifiable)

class Sprite
{
  ...
};

class SpriteBatch
{
private:
  std::vector<Sprite*> sprites;

public:
  const std::vector<Sprite*>& const getSprites() { return sprites; }
}

entity_sprite.h

#include "gfx_engine.h"

class EntitySprite : public Sprite
{
private:
  Entity *entity;

public:
  ...
  void setEntity(Entity* entity) { this->entity = entity; }
  Entity* getEntity() { return entity; }
};

entities.h

class SpriteBatch;

template<typename T>
class EntityCollection
{
private:
  SpriteBatch* batch;

public:
  class const_iterator
  {
  private:
    std::vector<Sprite*>::const_iterator inner;

  public:
    const_iterator(const std::vector<Sprite*>::const_iterator& it) : inner(it) { }

    inline bool operator!=(const const_iterator& other) const { return inner != other.inner; }
    inline const const_iterator& operator++() { ++inner; return *this; }
    T* operator*() const;
  };

  const_iterator begin() const;
  const_iterator end() const;

  EntityCollection() : batch(nullptr) { }
  explicit EntityCollection(SpriteBatch* batch) : batch(batch) { }
};

entities.cpp

#include "Entities.h"
#include "EntitySprite.h"

template<typename T> 
typename EntityCollection<T>::const_iterator EntityCollection<T>::begin() const { return const_iterator(batch->getChildren().cbegin()); }
template<typename T> 
typename EntityCollection<T>::const_iterator EntityCollection<T>::end() const { return const_iterator(batch->getChildren().cend()); }
template<typename T>
T* EntityCollection<T>::const_iterator::operator*() const { return static_cast<T*>(static_cast<EntitySprite*>(*inner)->getEntity()); }

Now, this works (I can do for (Entity* entity : entities) but it has 2 drawbacks:

  • I'm forced to include EntitySprite.h in Entities.cpp which should be a logic only file (minor drawback)
  • I need to implement operator*() overload in a source file to avoid including EntitySprite.h (and consequently the whole gfx engine) inside Entities.h , but I want to avoid such a trivial function to be non inlined

The problem is that the compiler is unable to inline or optimize the call to operator* (I already checked the -O2 generated binary) but this operation is done on thousands of entities 60 times per second so to obtain encapsulation I have to trade it for perfomance.

I'm trying to avoid this but I haven't come with a good solution yet. The only idea that came into my mind is to exploit multiple inheritance and reinterpret_cast , sort of

class EntitySpriteBase
{
private:
  Entity* entity;
public:
  void setEntity(Entity* entity) { ... }
  Entity* getEntity() { ... }
}

class EntitySprite : public EntitySpriteBase, public Sprite { ... }

T* EntityCollection<T>::const_iterator::operator*() const { return static_cast<T*>(reinterpret_cast<EntitySpriteBase*>(*inner)->getEntity()); }

Any suggestions?

Just put EntitySprite.h in your header and be done with it. The only downside is slightly longer compilation times. If compilation time is important for development, then you can use #ifdef NDEBUG to do it both ways; one way in the declaration (header file) and one way in the implementation file (cpp).

This is a huge problem with the legacy of c seperation between declaration and definition files. It's so much easier in other languages where everything is always in one file and the compiler/linker sorts it out for you (ie C#).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM