Зарегистрировать класс на фабрике

У меня вопрос по поводу заводской выкройки. Я запрограммировал фабрику со статической функцией registerIt. Он принимает строку для имени класса и указатель на функцию создателя любого класса.

static void CharacterFactory::registerit(const std::string& classname, Creator creator)
{
   table[classname] = creator;
}

Таблица

std::map<std::string, CharacterFactory::Creator> CharacterFactory::table;

Создатель

typedef std::auto_ptr<Actor> Type;
typedef Type (*Creator)();

Актер — это базовый класс.

В самих классах есть функция регистрации. Например класс "Игрок"

static void registerToFactory(){
    CharacterFactory::registerit("Player",&create);
    std::cout<<"player created"<<std::endl;     
    }

Моя проблема в том, как я могу сказать классам зарегистрироваться на статической фабрике? Все работает, если я вызываю registerToFactory в основном классе. Но я хочу сделать это более динамично, поэтому мне нужно изменить код только в новых классах, а не везде в моем коде.

Весь код ниже:

Фабрика.ч:

#pragma once
#include "Actor.h"
#include <string>
#include<map>
namespace Character{
class Actor;
class CharacterFactory
{

public:
typedef std::auto_ptr<Actor> Type;
typedef Type (*Creator)();

CharacterFactory(void);
~CharacterFactory(void);

Type create(const std::string& classname);
static void registerit(const std::string& classname, Creator creator);

private:
static std::map<std::string, Creator> table;
};
}

Актер:

#pragma once
#include<string>
#include"CharacterFactory.h"
#include<iostream>
namespace Character{

class Actor
{
public:

static Actor* create(){std::cout<<"dummy"<<std::endl;return NULL;};
static Actor* create(int dmg){std::cout<<"dummy"<<std::endl;return NULL;};

Actor(void):damage(0),healthPoints(0),lastUpdate(0){};
Actor(int dmg):damage(dmg){};
~Actor(void);

virtual void update(void)=0;
virtual void update(int deltaMillis)=0;

protected:

int lastUpdate;


//Attribute
int healthPoints;
int damage;
//Amor amor;
//Weapon weapon;
//Ai ai;


//Networking

};

}

Игрок:

#pragma once
#include "Actor.h"
#include <stdio.h>
#include "CharacterFactory.h"

namespace Character{
#ifndef PLAYER_H
#define PLAYER_H
class Player:public Actor
{
public:

void update(void){};
void update(int deltaMillis){};


static std::auto_ptr<Actor> create(){
    return std::auto_ptr<Actor>(new Player);
}
Player(void);

~Player(void);
static void registerToFactory(){
        CharacterFactory::registerit("Player",&create);
        std::cout<<"player created"<<std::endl;     
    }
inline int getDamage(void){ return damage;};
};
#endif
}

Я надеюсь, что вы можете помочь мне :)


person Christian    schedule 10.02.2014    source источник
comment
Вы можете сделать это в конструкторе статического объекта (нового класса, который вы должны написать). Тогда вам не нужно трогать свою основную функцию каждый раз, когда добавляется новый класс. Вам все еще нужно где-то определить эти статические объекты, по одному для каждого класса.   -  person n. 1.8e9-where's-my-share m.    schedule 10.02.2014
comment
если я вставлю static Player player после всего кода в player.h, я получу ошибку в xtree? Можете ли вы привести мне пример, пожалуйста? я хотел бы создать статический объект в своем классе или где-то в файле .cpp   -  person Christian    schedule 10.02.2014
comment
Я пробовал обходной путь. Есть функция loadCharacters(). Он создает статические объекты каждого персонажа, поэтому вызывается конструктор. Затем я создал экземпляр factory. В его конструкторе вызывается функция. поэтому мне нужно только изменить статические экземпляры в функции. Но у меня есть фабричный объект, который мне не нужен.   -  person Christian    schedule 10.02.2014
comment
Дай мне попробовать снова. Вы можете сделать это в конструкторе статического объекта (нового класса, который вы должны написать). Не статические объекты класса Player. И вы никогда не добавляете определения объектов в файл .h.   -  person n. 1.8e9-where's-my-share m.    schedule 10.02.2014
comment
Извините, неправильно понял. Теперь это работает, спасибо!   -  person Christian    schedule 10.02.2014
comment
Чтобы сделать это немного более явным: этот новый класс, назовите его RegistryRunner, должен принимать строку и функцию в качестве аргументов своего конструктора. Затем он регистрирует их на заводе. Таким образом, когда добавляется новый класс, вместе с ним добавляется новый RegistryRunner статический объект. Существующий код трогать нельзя.   -  person n. 1.8e9-where's-my-share m.    schedule 10.02.2014


Ответы (1)


Вы можете использовать либо конструктор, либо выражение динамической инициализации для статической переменной, и компилятор обеспечит выполнение до вызова main().

person Tony Delroy    schedule 10.02.2014