Регистрирайте самия клас във фабриката

Имам въпрос относно фабричната кройка. Програмирах фабрика, която има статична функция, наречена 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 в основния клас. Но искам да го направя по-динамично, така че трябва да променя кода само в новите класове, а не навсякъде в моя код.

Целият код по-долу:

Factory.h:

#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(). Той създава статични обекти от всеки символ, така че се извиква конструкторът. След това създадох екземпляр на фабриката. В своя конструктор функцията се извиква. така че трябва да променя само статичните екземпляри във функцията. Но имам фабричен обект, който не ми трябва.   -  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