Looking for a better C++ class factory

前端 未结 10 672
伪装坚强ぢ
伪装坚强ぢ 2020-12-29 00:40

I have an application that has several objects (about 50 so far, but growing). There is only one instance of each of these objects in the app and these instances get shared

相关标签:
10条回答
  • 2020-12-29 01:22

    If you have RTTI enabled, you can get the class name using typeid.

    One question, why are you using a factory rather than using a singleton pattern for each class?


    Edit: OK, so you don't want to be locked into a singleton; no problem. The wonderful thing about C++ is it gives you so much flexibility. You could have a GetSharedInstance() member function that returns a static instance of the class, but leave the constructor public so that you can still create other instances.

    0 讨论(0)
  • 2020-12-29 01:30

    If you always know the type at compile time there is little point in calling BrokeredObject* p = GetObjectByID(TypeA::get_InterfaceID()) instead of TypeA* p = new TypeA or TypeA o directly.

    If you on the other hand don't know the exact type at compile time, you could use some kind of type registry.

    template <class T>
    BrokeredObject* CreateObject()
    {
        return new T();
    }
    
    typedef int type_identity;
    typedef std::map<type_identity, BrokeredObject* (*)()> registry;
    registry r;
    
    class TypeA : public BrokeredObject
    {
    public:
         static const type_identity identity;
    };
    
    class TypeB : public BrokeredObject
    {
    public:
         static const type_identity identity;
    };
    
    r[TypeA::identity] = &CreateObject<TypeA>;
    r[TypeB::identity] = &CreateObject<TypeB>;
    

    or if you have RTTI enabled you could use type_info as type_identity:

    typedef const type_info* type_identity;
    typedef std::map<type_identity, BrokeredObject* (*)()> registry;
    registry r;
    
    r[&typeid(TypeA)] = &CreateObject<TypeA>;
    r[&typeid(TypeB)] = &CreateObject<TypeB>;
    

    Each new class could of course, in any case, be self-registering in the registry, making the registration decentralized instead of centralized.

    0 讨论(0)
  • 2020-12-29 01:30

    My use-case tended to get a little more complex - I needed the ability to do a little bit of object initialization and I needed to be able to load objects from different DLLs based on configuration (e.g. simulated versus actual for hardware). It started looking like COM and ATL was where I was headed, but I didn't want to add the weight of COM to the OS (this is being done in CE).

    What I ended up going with was template-based (thanks litb for putting me on track) and looks like this:

    class INewTransModule
    {
      public:
        virtual bool Init() { return true; }
        virtual bool Shutdown() { return true; }
    };
    
    template <typename T>
    struct BrokeredObject
    {
    public:
        inline static T* GetInstance()
      {
        static T t;
        return &t;
      }
    };
    
    template <> 
    struct BrokeredObject<INewTransModule>
    {
    public:
        inline static INewTransModule* GetInstance()
      {
        static INewTransModule t;
        // do stuff after creation
        ASSERT(t.Init());
        return &t;
      }
    };
    
    class OBJECTBROKER_API ObjectBroker
    {
      public: 
        // these calls do configuration-based creations
        static ITraceTool  *GetTraceTool();
        static IEeprom     *GetEeprom();
        // etc
    };
    

    Then to ensure that the objects (since they're templated) actually get compiled I added definitions like these:

    class EepromImpl: public BrokeredObject<EepromImpl>, public CEeprom
    {
    };
    
    class SimEepromImpl: public BrokeredObject<SimEepromImpl>, public CSimEeprom
    {
    };
    
    0 讨论(0)
  • 2020-12-29 01:34

    Use a template class as the broker.
    Make the instance a static member of the function. It will be created on first use and automagically-destroyed when the program exits.

    template <class Type>
    class BrokeredObject
    {
        public:
            static Type& getInstance()
            {
                static Type theInstance;
    
                return theInstance;
            }
    }; 
    
    class TestObject
    {
        public:
           TestObject()
           {}
    };
    
    
    int main()
    {
        TestObject& obj =BrokeredObject<TestObject>::getInstance();
    }
    
    0 讨论(0)
提交回复
热议问题