其他类的初始化类 - C ++

时间:2012-06-05 21:52:11

标签: c++ design-patterns

我想初始化两个注册一些值(A,B)的类(比如Class ARegister,Class BRegister)。我想从超级(?)类(比如Class RegisterALL)初始化这两个类。

Ex:RegisterALL类将初始化ARegister和BRegister。因此,任何使用该模块的人都不需要单独创建ARegister和BRegister的对象,而是可以创建RegisterALL的对象。

我想在构造函数中执行所有这些注册。因此,所有需要做的就是创建RegisterALL类的对象,并自动进行注册。

我们不在项目中使用例外。因此,如果注册中存在一些错误,则无法知道。

我是否应该有单独的成员函数来进行注册或让构造函数进行注册。

我是OO设计的新手。我觉得设计有问题,如果你能指出正确的方法,将会有所帮助。

2 个答案:

答案 0 :(得分:3)

最好的方法是使用CRTP(奇怪的重复模板模式),派生类ARegister和BRegister将自己作为模板参数传递给基类RegisterALL。 它看起来像这样:

class RegisterAll
{
public:
    template<class DerivedType>
    DerivedType *createType()
    {
        RegisterAll *r = (*(m_creators[DerivedType::id]))();
        return dynamic_cast<DerivedType *>(r); //static_cast will work too if you didn't make a mistake
    }
protected:
    static std::map<int,RegisterAll *(*)()> m_creators;
};

std::map<int,RegisterAll *(*)()> RegisterAll::m_creators = std::map<int,RegisterAll *(*)()>();

template<class Derived>
class CRTPRegisterAll : public RegisterAll
{
public:
    static bool register() 
    {
        RegisterAll::m_creators.push_back(std::make_pair(Derived::id,Derived::create);
        return true;
    }

private:
    static bool m_temp;
};

template<class Derived>
bool CRTPRegisterAll<Derived>::m_temp = CRTPRegisterAll<Derived>::register();

class RegisterA : public CRTPRegisterAll<RegisterA>
{
private:
    static RegisterA *create() 
    {
        //do all initialization stuff here
        return new RegisterA;
    }

public:
    static const int id = 0;
};

现在,m_temp中静态变量CRTPRegisterAll的初始化将每个派生类型的创建者函数推送到RegisterAll列表中。让RegisterAll知道所有派生类(它不是非常可扩展的)通常不是很好的设计。这样,实际的创建方法可以在每个派生类中实现,创建者函数将自动在RegisterAll中注册。 CRTP的一个主要优点是派生类不需要知道如何将自己注册到基类列表,它是为它们完成的。至于错误处理,也可以在每个派生类的创建者函数中实现。有更好的方法来处理id问题,但我不想在这里进入。 如果你想要一个更简单的方法,我建议阅读有关工厂设计模式的内容。

答案 1 :(得分:3)

您似乎已经决定了对象之间的某种关系。但是,你只是模糊地描述了这种关系。

如果RegisterALL使用的是简单的遏制,那么您将拥有一个非常简单的关系。这种关系可能表达如下(请原谅ASCII图形):

       +-------------+
       | RegisterALL |               --> := has
       +-------------+
          |       |
          v       v
+-----------+   +-----------+
| ARegister |   | BRegister |
+-----------+   +-----------+

优点是两个家属的图片非常简单。但是,如果您要注册许多对象,那么图片看起来就像是RegisterALL爆炸成一堆XRegister个对象。

如果RegisterALL包含ARegisterBRegister,您可能需要为ARegisterBRegister创建公共基类,以便RegisterALL 1}}可以维护一个容器。

      +-------------+      +------------------+            <>--> := aggregates
      | RegisterALL |<>--->| AbstractRegister |              
      +-------------+      +------------------+              |
                                    |                      _/_\_ := inherits
                                   / \
                               ___/___\___
                               |         |
                    +-----------+       +-----------+
                    | ARegister |       | BRegister |
                    +-----------+       +-----------+

我们发现,无论注册了多少新项目,RegisterALLAbstractRegister之间的关系都保持不变。我们可以更进一步,从模板中派生ARegisterBRegister

      +-------------+      +------------------+
      | RegisterALL |<>--->| AbstractRegister |
      +-------------+      +------------------+
                                    |
                                   / \
                                  /___\
                                    |
                                    |     +--------------+
                           +--------------| RegisterType |
                           |              +--------------+
                           | RegisterTemplate |
                           +------------------+

好的,OO设计课程非常多。这很快转化为代码。让我们从简单的事情开始吧。 RegisterType枚举要注册的不同内容。 RegisterTypeName和重载运算符允许代码在打印RegisterType时打印字符串而不是数字。

enum RegisterType { A, B, MAX_RegisterType };

static inline std::string
RegisterTypeName (RegisterType t)
{
    static const char * names[] = { "A", "B" };
    return names[t];
}

static inline std::ostream &
operator << (std::ostream &output, RegisterType t)
{
    return output << RegisterTypeName(t);
}

AbstractRegister提供了一个查询此类型的接口。此外,poke接口提供了默认实现。注意在C ++中,抽象类型应该提供虚拟析构函数。

class AbstractRegister {
public:
    virtual ~AbstractRegister () {}
    virtual RegisterType type () const = 0;
    virtual void poke () { std::cout << "Poked " << type(); }
};

typedef std::unique_ptr<AbstractRegister> AbstractRegisterPtr;
static const AbstractRegisterPtr AbstractRegisterNullPtr;

RegisterALL类有一个容器来容纳AbstractRegister类型的东西。它使用地图将RegisterTypeAbstractRegister实例相关联,我们将其作为注册。 RegisterALL实现为单例,这意味着它只允许自身的一个实例。 add方法执行注册,find方法允许找到已注册的实例。 RegisterALL构造函数的实现推迟到定义RegisterTemplate之后。

class RegisterALL {
    template <RegisterType> friend class RegisterTemplate;
    typedef std::unique_ptr<RegisterALL> SelfPtr;
    typedef std::map<RegisterType, AbstractRegisterPtr> RegisterMap;
    void add (AbstractRegister *r) { all[r->type()] = AbstractRegisterPtr(r); }
    RegisterALL ();
public:
    static const SelfPtr & instance () {
        if (!one) new RegisterALL;
        return one;
    }
    const AbstractRegisterPtr & find (RegisterType t) const {
        RegisterMap::const_iterator i = all.find(t);
        return (i != all.end()) ? i->second : AbstractRegisterNullPtr;
    }
private:
    static SelfPtr one;
    RegisterMap all;
};

RegisterALL::SelfPtr RegisterALL::one;

RegisterTemplate类派生自AbstractRegister,并由RegisterType参数化。它通过返回其模板参数的值来实现type虚方法。它也使用单例,但它不公开其实例。相反,它的实例由RegisterALL管理。它提供了使用register_type注册自己的RegisterALL方法,只有使用find上的RegisterALL方法才能找到此实例。

template <RegisterType RT>
class RegisterTemplate : public AbstractRegister {
    RegisterType type () const { return RT; }
    void poke () {
        std::cout << "Poked " << RegisterTypeName(RT) << std::endl;
    }
    RegisterTemplate () {
        std::cout << "Created " << RegisterTypeName(RT) << std::endl;
    }
    ~RegisterTemplate () {
        std::cout << "Destroying " << RegisterTypeName(RT) << std::endl;
    }
public:
    static void register_type () {
        if (RegisterALL::instance()->find(RT)) {
            std::cout << "Already registered " << RegisterTypeName(RT)
                      << std::endl;
            return;
        }
        RegisterALL::instance()->add(new RegisterTemplate<RT>);
    }
};

RegisterALL构造函数使用辅助模板register_all迭代RegisterType枚举,并实例化相应的RegisterTemplate,从而导致所有RegisterTypeRegisterALL注册。

template <unsigned X>
struct register_all {
    register_all () {
        RegisterTemplate<static_cast<RegisterType>(X)>::register_type();
        register_all<X+1>();
    }
};

template <> struct register_all<MAX_RegisterType> {};

inline RegisterALL::RegisterALL ()
{
    one = std::move(SelfPtr(this));
    register_all<0>();
}

所以要试一试,我们使用以下代码:

RegisterALL::instance();                  // registers all RegisterType's
RegisterTemplate<B>::register_type();     // try to register B again
RegisterALL::instance()->find(A)->poke(); // poke at A

这是输出:

Created A
Created B
Already registered B
Poked A
Destroying B
Destroying A

注意智能指针如何自动清理我们注册的项目。