Способ 1. Наследование.
class Entity
{
public:
virtual ~Entity() {} // для корректной работы динамических структур данных
// наподобие менеджеров уровней; в нашем примере не нужно;
// в реальной игре потребуется
}
class Player : public Entity
{
public:
bool isDead;
}
int main()
{
Player player;
player.isDead = true;
return 0;
}
Если кто-то отдаёт Entity, окторый гарантированно Player — то
Player& somePlayer = dynamic_cast<Player&>(someEntity);
Способ 2. Композиция
class Player
{
public:
Entity entity;
bool isDead;
}
Способ 3. Словарь. Это уже на случай, когда чужой код настолько монолитный, что ничем его не прошибёшь.
struct PlayerInfo
{
bool isDead;
}
std::map<const Entity*, PlayerInfo> playerInfo;
Если чужой код монолитный, а объекты ещё и перемещаются по памяти — тогда выяснить, что будет «значением» объекта (например, какой-нибудь идентификатор).
typedef std::string PlayerId;
std::map<PlayerId, PlayerInfo> playerInfo;
Если и код монолитный, и «имя» или «значение» объекту никак не придумаешь — тогда никак.