0

我正在使用 c++98。我想创建一个基于模板的通用工厂,创建者可以不带参数来创建目标对象,也可以只带一个参数。

/*<class.h> begins

#ifndef INCLUDED_CLASS
#define INCLUDED_CLASS

#include <iostream>
#include <boost/shared_ptr.hpp>

class A
{
public:
    A() { _a = 27; }
    void print() const { std::cout << "A is " << _a << "." << std::endl; }
protected:
    int _a;
};
typedef boost::shared_ptr<A> APtr;

class AA : public A
{
public:
    void print() const { std::cout << "AA is " << _a << "!" << std::endl; }
};

class B
{
public:
    B(double b) { _b = b; }
    void print() const { std::cout << "B is " << _b << "." << std::endl; }
protected:
    double _b;
};
typedef boost::shared_ptr<B> BPtr;

class BB : public B
{
public:
    BB(double b) : B(b) {};
    void print() const { std::cout << "BB is " << _b << "!" << std::endl; }
};

#endif

/*<class.h> ends



/*<factory.h> begins

#ifndef INCLUDED_FACTORY
#define INCLUDED_FACTORY

#include <map>
#include <string>
#include <boost/shared_ptr.hpp>

template<class bT, class pT=void>
class Creator
{
public:
    virtual bT* create() = 0;
    virtual bT* create(const pT* param) = 0;
};

template <class bT, class pT>
struct CreatorPtr
{
    typedef boost::shared_ptr< Creator<bT> > type;
};


template <class bT, class cT, class pT>
class CreatorImpl : public Creator<bT, pT>
{
public:
   virtual bT* create() { return new cT; }
   virtual bT* create(const pT* param) { return new cT(param); }
};


template<class bT, class pT=void>
class Factory
{
public:
    virtual bT* create(const std::string& name) const = 0;
    virtual bT* create(const std::string& name, const pT* param) const = 0;
protected:
    Factory() {}
    Factory(const Factory&) {}
    Factory &operator=(const Factory&) { return *this; }
    void registerCreator(const std::string& name, typename CreatorPtr<bT, pT>::type creator)
        { _table_creator[name] = creator; }
    typedef std::map<std::string, typename CreatorPtr<bT, pT>::type> tableCreator;
    typedef typename tableCreator::const_iterator citerTc;
    citerTc begin() const { return _table_creator.begin(); }
    citerTc end() const { return _table_creator.end(); }
    citerTc find(const std::string& name) const { return _table_creator.find(name); }
protected:
    tableCreator _table_creator;
};

class A;
class EngineA : public Factory<A>
{
public:
    virtual A* create(const std::string& name) const
    {
        citerTc it = find(name);
        if (it != end() && it->second)
        {
            return it->second->create();
        }
        else
            return (A*)NULL;
    }

    static Factory<A>& get()
    {
        static EngineA instance;
        instance.registerEngine();
        return instance;
    }
private:
    virtual A* create(const std::string& name, const void* param) const { return (A*)NULL; }
private:
    virtual void registerEngine();
};

void EngineA::registerEngine()
{
    CreatorPtr<A, void>::type AACreator(new CreatorImpl<A, AA, void>);
    registerCreator("AA", AACreator);
}

class B;
class EngineB : public Factory<B, double>
{
public:
    virtual B* create(const std::string& name, const double* value) const
    {
        citerTc it = find(name);
        if (it != end() && it->second && value)
        {
            return it->second->create(value);
        }
        else
            return (B*)NULL;
    }

            static Factory<B, double>& get()
    {
        static EngineB instance;
        instance.registerEngine();
        return instance;
    }
private:
    virtual B* create(const std::string& name) const { return (B*)NULL; }
private:
    virtual void registerEngine();
};

void EngineB::registerEngine()
{
    CreatorPtr<B, double>::type BBCreator(new CreatorImpl<B, BB, double>);
    registerCreator("BB", BBCreator);
}

#endif

/*<factory.h> ends



/*<main.cpp> begins

#include <class.h>
#include <factory.h>

int main(void)
{
    APtr a(EngineA::get().create("AA"));
    if (a)
        a->print();

    double value = 35.7;
    BPtr b(EngineB::get().create("BB",&value));
    if (b)
        b->print();

    return 0;
}

/*<main.cpp> ends

编译错误是:

....../boost//boost_1_46_1/include/boost/smart_ptr/shared_ptr.hpp: In constructor ‘boost::shared_ptr<T>::shared_ptr(Y*) [with Y = CreatorImpl<B, BB, double>, T = Creator<B, void>]’:
./factory.h:116:   instantiated from here
....../boost//boost_1_46_1/include/boost/smart_ptr/shared_ptr.hpp:187: error: cannot convert ‘CreatorImpl<B, BB, double>*’ to ‘Creator<B, void>*’ in initialization
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create() [with bT = B, cT = BB, pT = double]’:
main.cpp:15:   instantiated from here
./factory.h:27: error: no matching function for call to ‘BB::BB()’
./class.h:36: note: candidates are: BB::BB(double)
./class.h:34: note:                 BB::BB(const BB&)
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create(const pT*) [with bT = B, cT = BB, pT = double]’:
main.cpp:15:   instantiated from here
./factory.h:28: error: no matching function for call to ‘BB::BB(const double*&)’
./class.h:36: note: candidates are: BB::BB(double)
./class.h:34: note:                 BB::BB(const BB&)
./factory.h: In member function ‘bT* CreatorImpl<bT, cT, pT>::create(const pT*) [with bT = A, cT = AA, pT = void]’:
main.cpp:15:   instantiated from here
./factory.h:28: error: no matching function for call to ‘AA::AA(const void*&)’
./class.h:18: note: candidates are: AA::AA()
./class.h:18: note:                 AA::AA(const AA&)
make: *** [test] Error 1

任何人都可以帮助解决错误吗?这是创建基于通用模板的工厂的好方法吗?

4

2 回答 2

0

在此处查看我的答案以获取类似信息:https ://stackoverflow.com/a/18253631/2288854

该代码使用宏来生成一个通用工厂模板,该模板最多需要 N 个参数。它在 c++98 中不起作用,但也许它可以给你一些想法。

于 2013-08-26T11:38:48.883 回答
0

第一个错误:

typedef boost::shared_ptr< Creator<bT> > type;

您忘记通过 pT:

typedef boost::shared_ptr< Creator<bT,pT> > type;

第二:

virtual bT* create(const pT* param) { return new cT(param); }

在 create 中接受引用,或者将取消引用的指针传递给构造函数:

virtual bT* create(const pT& param) { return new cT(param); } // and change the other parts of the code accordingly to accept reference instead of pointer
// or:
virtual bT* create(const pT* param) { return new cT(*param); }

更大的问题是,在这种方法中,create 的两个版本都是为给定的 cT 生成的,并且由于缺少构造函数重载而无法编译。

专门处理 void,只保留那些有意义的 create 重载。这种方法有效:

#ifndef INCLUDED_CLASS
#define INCLUDED_CLASS

#include <iostream>
#include <boost/shared_ptr.hpp>


class A
{
public:
    A() { _a = 27; }
    void print() const { std::cout << "A is " << _a << "." << std::endl; }
protected:
    int _a;
};
typedef boost::shared_ptr<A> APtr;

class AA : public A
{
public:
    void print() const { std::cout << "AA is " << _a << "!" << std::endl; }
};

class B
{
public:
    B(double b) { _b = b; }
    void print() const { std::cout << "B is " << _b << "." << std::endl; }
protected:
    double _b;
};
typedef boost::shared_ptr<B> BPtr;

class BB : public B
{
public:
    BB(double b) : B(b) {};
    void print() const { std::cout << "BB is " << _b << "!" << std::endl; }
};

#endif

// ----

#ifndef INCLUDED_FACTORY
#define INCLUDED_FACTORY

#include <map>
#include <string>
#include <boost/shared_ptr.hpp>

template<class bT, class pT = void>
class Creator
{
public:
    virtual bT* create(const pT* param) = 0;
};

template<class bT>
class Creator<bT>
{
public:
    virtual bT* create() = 0;
};

template <class bT, class pT = void>
struct CreatorPtr
{
    typedef boost::shared_ptr< Creator<bT,pT> > type;
};
template <class bT>
struct CreatorPtr<bT>
{
    typedef boost::shared_ptr< Creator<bT> > type;
};


template <class bT, class cT, class pT = void>
class CreatorImpl : public Creator<bT, pT>
{
public:
    virtual bT* create(const pT* param) { return new cT(*param); }
};
template <class bT, class cT>
class CreatorImpl<bT,cT> : public Creator<bT>
{
public:
    virtual bT* create() { return new cT; }
};

template<class CreatorPtrType>
class FactoryBase
{
protected:
    FactoryBase() {}
    FactoryBase(const FactoryBase&) {}
    FactoryBase &operator=(const FactoryBase&) { return *this; }
    void registerCreator(const std::string& name, CreatorPtrType creator)
    { _table_creator[name] = creator; }
    typedef std::map<std::string, CreatorPtrType> tableCreator;
    typedef typename tableCreator::const_iterator citerTc;
    citerTc begin() const { return _table_creator.begin(); }
    citerTc end() const { return _table_creator.end(); }
    citerTc find(const std::string& name) const { return _table_creator.find(name); }
protected:
    tableCreator _table_creator;
};


template<class bT, class pT = void>
class Factory : public FactoryBase<typename CreatorPtr<bT, pT>::type>
{
public:
    virtual bT* create(const std::string& name, const pT* param) const = 0;
};
template<class bT>
class Factory<bT> : public FactoryBase<typename CreatorPtr<bT>::type>
{
public:
    virtual bT* create(const std::string& name) const = 0;
};

class A;
class EngineA : public Factory<A>
{
public:
    virtual A* create(const std::string& name) const
    {
        citerTc it = find(name);
        if (it != end() && it->second)
        {
            return it->second->create();
        }
        else
            return (A*)NULL;
    }

    static Factory<A>& get()
    {
        static EngineA instance;
        instance.registerEngine();
        return instance;
    }
private:
    virtual void registerEngine();
};

void EngineA::registerEngine()
{
    CreatorPtr<A>::type AACreator(new CreatorImpl<A, AA>);
    registerCreator("AA", AACreator);
}

class B;
class EngineB : public Factory<B, double>
{
public:
    virtual B* create(const std::string& name, const double* value) const
    {
        citerTc it = find(name);
        if (it != end() && it->second && value)
        {
            return it->second->create(value);
        }
        else
            return (B*)NULL;
    }

    static Factory<B, double>& get()
    {
        static EngineB instance;
        instance.registerEngine();
        return instance;
    }
private:
    virtual void registerEngine();
};

void EngineB::registerEngine()
{
    CreatorPtr<B, double>::type BBCreator(new CreatorImpl<B, BB, double>);
    registerCreator("BB", BBCreator);
}

#endif

// ----

#include <class.h>
#include <factory.h>

int main(void)
{
    APtr a(EngineA::get().create("AA"));
    if (a)
        a->print();

    double value = 35.7;
    BPtr b(EngineB::get().create("BB",&value));
    if (b)
        b->print();

    return 0;
}
于 2013-05-06T22:59:47.867 回答