c++对象工厂

一.简单工厂

#pragma once

struct IObjectA
{
    virtual void Test1()=0;
};

class ObjectA:public IObjectA
{
public:
    virtual void Test1(){}
};

struct IObjectB
{
    virtual void Test2()=0;
};

class ObjectB:public IObjectB
{
public:
    virtual void Test2(){}
};

class ObjectFactory
{
public:
    static void Create(int nFlag,void** ppVoid)
    {
        switch (nFlag)
        {
        case 1:
            {
                IObjectA *pA=new ObjectA;
                *ppVoid=pA;
            }
            break;
        case 2:
            {
                IObjectB *pB=new ObjectB;
                *ppVoid=pB;
            }
            break;
        }
    }
};

class ObjectTest
{
public:
    ObjectTest();
    ~ObjectTest();

    static void Test1()
    {
        IObjectA *pA=nullptr;
        ObjectFactory::Create(1,(void**)&pA);
        pA->Test1();
    }
};

优缺点:这种工厂适用于对象不多的情况下,否则工厂类必须要知道所有类

对于一个比较大的项目如果有较多的对象就不适合了

二.使用__uuidof简化类型创建

借助这个关键字,可以为一个类指定一个guid

[
    uuid("F5844C2A-50D1-4F2C-85DB-429729927F0F")
]
struct IObjectA
{
    virtual void Test1()=0;
};

如下代码:

template<typename T>
    static T* Create()
    {
        GUID id=__uuidof(T);
        if(IsEqualGUID(id,__uuidof(IObjectA)))
        {
            IObjectA *pA=new ObjectA;
            return (T*)pA;
        }
        else if(IsEqualGUID(id,__uuidof(IObjectB)))
        {
            IObjectB *pB=new ObjectB;
            return (T*)pB;
        }
        return nullptr;
    }

    static void Test2()
    {
        IObjectA *pA=ObjectFactory::Create<IObjectA>();
        pA->Test1();
    }

以上的使用方式对外确实便利了很多

下面来解决if else的问题,

三.使用map来存储

1.由于map要使用guid来作为key,那么就需要一个比较函数

来看一下IsEqualGUID的实现,实际是一个宏,对字符串的比较

__inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
{
    return !memcmp(&rguid1, &rguid2, sizeof(GUID));
}

2.为了可以灵活创建对象,我们可以使用函数指针来创建对象

基于以上2点,我们创建来以下数据结构

typedef void (*CreateFunc)(void** ppVoid);
    struct guidCompare
    {
        bool operator () (GUID rguid1,GUID rguid2) const
        {
            return memcmp(&rguid1, &rguid2, sizeof(GUID))< 0;
        }
    };
    static std::map<GUID,CreateFunc,guidCompare> m_mapObj;

接着要初始化各个对象的创建函数

template<typename T,typename I>
    static void CreateInstance(void** ppVoid)
    {
        I *pObject=new T;
        *ppVoid=pObject;
    }

    static void Init()
    {
        m_mapObj.insert(std::map<GUID,CreateFunc>::value_type
            (__uuidof(IObjectA),CreateInstance<ObjectA,IObjectA>));
        m_mapObj.insert(std::map<GUID,CreateFunc>::value_type
            (__uuidof(IObjectB),CreateInstance<ObjectB,IObjectB>));
    }

3.再次改造一个Create方法

template<typename T>
    static T* CreateFromMap()
    {
        GUID id=__uuidof(T);

        std::map<GUID,CreateFunc>::iterator iter=m_mapObj.find(id);
        if(iter!=m_mapObj.end())
        {
            T* pObject=NULL;
            iter->second((void**)&pObject);
            return pObject;
        }

        return nullptr;
    }

4.测试代码

static void Test3()
    {
        ObjectFactory::Init();
        IObjectA *pA=ObjectFactory::CreateFromMap<IObjectA>();
        pA->Test1();
    }

以上步骤不再用一个一个的判断对象的guid,唯一的问题点在于初始化的问题

四.借助全局对象初始化来注册

封装一个Register方法

template<typename T,typename I>
    static void Register()
    {
        m_mapObj.insert(std::map<GUID,CreateFunc>::value_type
            (__uuidof(I),CreateInstance<T,I>));
    }

    Register<ObjectA,IObjectA>();

如果直接全局来调用这个方法的话显的有些暴力,而且容易出错,重复注册,可以借助一个辅助类在构造函数内完成

class ObjectACreateHelper
 {
 public:
     ObjectACreateHelper()
     {
         ObjectFactory::Register<ObjectA,IObjectA>();
     }
 };
 class ObjectBCreateHelper
 {
 public:
     ObjectBCreateHelper()
     {
         ObjectFactory::Register<ObjectB,IObjectB>();
     }
 };
 ObjectACreateHelper g_ObjectACreateHelper;
 ObjectBCreateHelper g_ObjectBCreateHelper;

上面的代码就完成的差不多了,上面的代码就是力气活来,可以再想办法简化

五.使用宏和模板来简化注册

template<typename T,typename I>
class CObjectCreateHelper
{
public:
    CObjectCreateHelper()
    {
        ObjectFactory::Register<T,I>();
    }
};

#define REG_CREATEObject(T, I) CObjectCreateHelper g_##T;

,i>REG_CREATEObject(ObjectA,IObjectA)
REG_CREATEObject(ObjectB,IObjectB)

现在就全部完成了整个步骤的改造,此思想可以用到很多类似的对象创建方法,很管用

Original: https://www.cnblogs.com/Clingingboy/p/3407662.html
Author: Clingingboy
Title: c++对象工厂

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535450/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • dev c++ 无法单步调试

    遇到cout语句中有endl时,点击下一步无反应,需将endl改为’\n’ 或直接添加 #define endl ‘\n’ 替换qt…

    C++ 2023年5月29日
    049
  • (筆記) 如何寫入binary file某個byte連續n byte的值? (C/C++) (C)

    Abstract通常公司為了保護其智慧財產權,會自己定義檔案格式,其header區會定義每個byte各代表某項資訊,所以常常需要直接對binary檔的某byte直接進行寫入,且連續…

    C++ 2023年5月29日
    062
  • c++builder调用VC的dll以及VC调用c++builder的dll

    解析__cdecl,__fastcall, __stdcall 的不同:在函数调用过程中,会使用堆栈,这三个表示不同的堆栈调用方式和释放方式。比如说__cdecl,它是标准的c方法…

    C++ 2023年5月29日
    065
  • 聊聊 C++ 大一统的初始化运算符 {}

    一:背景 最近发现 C++ 中的类型初始化操作,没有 {} 运算符搞不定的,蛮有意思,今天我们就来逐一列一下各自的用法以及汇编展现,本来想分为 &#x503C;&#…

    C++ 2023年5月29日
    028
  • [C++] namespace命名空间和using用法

    命名空间namespace:指标识符的各种可见范围。 C++标准程序库中的所有标识符都被定义在一个std的namespace,这就是程序开始添加 using namespace s…

    C++ 2023年5月29日
    055
  • c++ typedef和#define的作用范围

    typedef: 如果放在所有函数之外,它的作用域就是从它定义开始直到文件尾; 如果放在某个函数内,定义域就是从定义开始直到该函数结尾; #define: 不管是在某个函数内,还是…

    C++ 2023年5月29日
    096
  • 当C++遇到iOS应用开发之—List集合

    在Object-c中,数组使用NSArray和NSMutableArray(可变长数组)。使用语法如下: NSArray *array = [[NSArray alloc] ini…

    C++ 2023年5月29日
    058
  • Google C++ 单元测试 GTest

    from : http://www.cnblogs.com/jycboy/p/6057677.html 一、设置一个新的测试项目 在用google test写测试项目之前,需要先编…

    C++ 2023年5月29日
    035
  • [C++] 引用类型&

    引用的方法: 类型 &引用名 = 变量名; 例如: int a = 5; int &b = a; 引用的规则: 1、引用被创建的同时必须被初始化 2、无null引用…

    C++ 2023年5月29日
    056
  • Windows Runtime——-面向对象化的c++(并非意味着托管)

    Windows8的开发平台总体上分为两部分:一是全新的WinRT,界面搭配Metro style,二是传统的Win32、.NET(SL)、IE三大平台,界面为传统窗体风格。其中全新…

    C++ 2023年5月29日
    074
  • C++ 模板类相关问题

    1.模板类中的函数定义与实现必须全部写在头文件中 C++中每一个对象所占用的空间大小,是在编译的时候就确定的,在模板类没有真正的被使用之前,编译器是无法知道,模板类中使用模板类型的…

    C++ 2023年5月29日
    048
  • [c++] 拷贝构造函数

    拷贝构造函数就是进行对象拷贝复制的函数。 拷贝构造函数也是一种构造函数。它用同类型的对象来初始化新创建的对象。其唯一的形参是const类型&,此函数也由系统自动调用。 拷贝…

    C++ 2023年5月29日
    049
  • (筆記) 如何寫入binary file某個byte的值? (C/C++) (C)

    Abstract通常公司為了保護其智慧財產權,會自己定義檔案格式,其header區會定義每個byte各代表某項資訊,所以常常需要直接對binary檔的某byte直接進行寫入。 In…

    C++ 2023年5月29日
    047
  • c++容器set

    class Solution { public: vector intersection(vector& nums1, vector& nums2) { // ve…

    C++ 2023年5月29日
    049
  • c++智能指针

    跟comptr类似 明确定义AddRef和Release,然后定义与comptr类似的一个辅助类. 这里有2种方式 1.Release的时候引用计数为0的时候删除对象 2.定义一个…

    C++ 2023年5月29日
    094
  • C++ 中 malloc/free与 new/delete区别

    new/delete 通常来说是操作符,就是”+”,”-“一样,malloc/free 是 C++/C 语言的标准库函数 —— 本质…

    C++ 2023年5月29日
    064
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球