2 votes

Initialiser une variable statique partagée par un groupe d'objets seulement C++

Je me demandais s'il était possible de créer un membre de données de classe partagé uniquement par un groupe d'objets de cette même classe.

J'ai une classe appelée Scène et un autre appelé Objet du jeu , La scène crée des GameObjects, et chaque GameObject créé doit avoir une référence à la scène qui l'a créé.

Je pourrais y parvenir en déclarant simplement :

class GameObject
{
    public:
        Scene* scene;
}

Et mis à chaque fois qu'une scène crée un objet de jeu.

void Scene::add_game_object(){
    GameObject* gameobject = new GameObject();
    gameobject->scene = this;
}

Mais, cela prendrait beaucoup de mémoire.

J'ai réfléchi à une solution (actuellement, je ne compile pas, mais nous pourrions peut-être en tirer quelque chose).

class GameObject
{
    public:
        template< Scene* S >
        Scene* get_scene();
}
//
template< Scene* S >
Scene* GameObject::get_scene(){
    static Scene* sc = nullptr;
    if( sc == nullptr ){
        sc = S;
    }
    return sc;
}

void Scene::add_game_object(){
    GameObject* gameobject = new GameObject();
    // link scene and gameobject.
    gameobject->get_scene(this);
}

L'utiliser :

gameobject->get_scene<nullptr>();

Merci. Cordialement.

3voto

m.s. Points 6209

Vous pouvez stocker le pointeur vers le Scene dans une variable statique de GameObject même si vous avez plusieurs Scene objets.

L'idée est d'avoir un types distincts pour chaque Scene ainsi que types distincts pour leur GameObject . Cela permet d'avoir un variable statique distincte pour chaque Scene où le pointeur peut être stocké.

Le code suivant met en œuvre cette idée. Il exige que le nombre maximum de Scenes est défini au moment de la compilation afin de remplir la table des pointeurs de fonction :

#include <cassert>
#include <array>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

// forward declaration
template <std::size_t N>
struct Scene;

template <std::size_t N>
struct GameObject
{
    GameObject()
    {
        std::cout << "created GameObject<" << N << "> which belongs to '" << scene->name << "'"<< std::endl;
    }
    static Scene<N>* scene;
};

template <std::size_t N>
Scene<N>* GameObject<N>::scene;

struct SceneBase
{
    virtual ~SceneBase() = default;
    virtual void addGameObject() = 0;
};

template <std::size_t N>
struct Scene : SceneBase
{
    using GO = GameObject<N>;
    Scene(const std::string& name) : SceneBase(), name(name)
    {
        GO::scene = this;
    }

    void addGameObject() override
    {
        gameObjects.push_back(std::make_unique<GO>());
    }

    std::vector<std::unique_ptr<GO>> gameObjects;
    std::string name;
};

template <std::size_t N>
struct SceneMaker
{
    static std::unique_ptr<SceneBase> make(const std::string& name)
    {
        std::cout << "making Scene<" << N <<"> with name '" << name << "'" << std::endl;
        return std::make_unique<Scene<N>>(name);
    }
};

using FunctionPtr = std::unique_ptr<SceneBase> (*)(const std::string&);

// based on http://stackoverflow.com/a/20408889/678093
template <std::size_t N, std::size_t... Rest>
struct FunctionTable
{
    static constexpr auto& value = FunctionTable<N - 1, N, Rest...>::value;
};

template <std::size_t... Rest>
struct FunctionTable<0, Rest...>
{
    static constexpr std::array<FunctionPtr,sizeof...(Rest)+1> value = {SceneMaker<0>::make,SceneMaker<Rest>::make...};
};

template <std::size_t... Rest>
constexpr std::array<FunctionPtr, sizeof...(Rest)+1> FunctionTable<0, Rest...>::value;

struct SceneFactory
{
    auto makeScene(const std::string& name)
    {
        assert(sceneIndex < maxScenes);
        return fTable[sceneIndex++](name);
    }

    static constexpr std::size_t maxScenes = 10;
    static constexpr auto& fTable = FunctionTable<maxScenes>::value;

    std::size_t sceneIndex = 0;
};

int main()
{
    SceneFactory factory;
    auto scene1 = factory.makeScene("first scene");
    scene1->addGameObject();
    scene1->addGameObject();
    auto scene2 = factory.makeScene("second scene");
    scene2->addGameObject();
    scene2->addGameObject();
}

sortie :

making Scene<0> with name 'first scene'
created GameObject<0> which belongs to 'first scene'
created GameObject<0> which belongs to 'first scene'
making Scene<1> with name 'second scene'
created GameObject<1> which belongs to 'second scene'
created GameObject<1> which belongs to 'second scene'

<a href="http://coliru.stacked-crooked.com/a/5df9857b69a247af" rel="nofollow">live example</a>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X