C++框架技术-根据类名动态创建类对象

背景

在构建C++框架时经常用到一项基础技术, 就是根据一个类名称字符串动态创建类对象, 这样可以实现即为彻底的解耦合, 比如常规的基于工厂方法的创建实例代码需要在工厂实现文件中去include各个子类头文件,并需要显式的去调用子类构造函数, 如下代码示例:

#include "A.h"
#include "B.h"
#include "C.h"

Base* Factory::CreateObject()
{
    Object* obj = nullptr;
    if(xxx)
    {
        obj = new A();
    }
    else if(xxx)
    {
        obj = new B();
    }
    else
    {
        obj = new C();
    }
    return obj;
}

这种写法每加入一个新的子类,都需要修改这个Create入口, 且无法实现配置化

而如果能支持一种根据类名动态创建类实例的能力,则将大大改善

如下示例,className可以通过配置化获取, 不需要显示调用子类的构造函数

Base* b = CreateObject(className);
b->Execute();

实现原理

核心元素:

一个管理支持动态创建能力类的工厂ObjectFactory类, 其中核心成员是一个map:

key:类名字符串  --> value:创建该类对象的函数指针

并提供2个核心函数:

1.注册某个类到map RegisterObj(类名字符串, 创建该类的函数指针)

2.创建对象 CreateObj(类名字符串)

类图:

 需要支持该能力的类继承Object类, 并注册创建自身实例的静态函数指针到ObjectFactory

 可以利用宏定义增加易用性

自动注册时机原理:

利用全局静态变量的初始化在main函数之前的原理, 对于此类支持动态创建的类,都增加一个静态变量初始化时驱动调用注册

static int g_tmp_xxx = ObjectFactory::GetInstance().RegisterObj("ClassName", ClassName::CreateObj);

实现代码

包含核心代码+简化实用的宏+单元测试

代码风格基于C++ 11

ObjectFactory.h

#ifndef __OBJECTFACTORY_H__
#define __OBJECTFACTORY_H__

#include <map>
#include <string>
#include <functional>

class Object
{
public:
    virtual std::string GetClassName() const = 0;
};

class ObjectFactory
{
public:
    static ObjectFactory& GetInstance();

    using ObjCreator = std::function<Object*(void)>;
    int RegisterObj(const std::string& className, ObjCreator objCreator);

    Object* CreateObj(const std::string& className);

private:
    ObjectFactory();
    ~ObjectFactory();
    ObjectFactory(const ObjectFactory&) = delete;

    std::map<std::string, ObjCreator> creatorMap_;
};

#endif

 ObjectFactory.cpp

#include "ObjectFactory.h"
using namespace std;

ObjectFactory& ObjectFactory::GetInstance()
{
    static ObjectFactory instance_;
    return instance_;
}

int ObjectFactory::RegisterObj(const std::string& className, ObjCreator objCreator)
{
    creatorMap_.insert(make_pair(className, objCreator));
    return 0;
}

Object* ObjectFactory::CreateObj(const std::string& className)
{
    auto it = creatorMap_.find(className);
    if(it == creatorMap_.end())
    {
        return nullptr;
    }
    return it->second();
}

ObjectFactory::ObjectFactory()
{
}

ObjectFactory::~ObjectFactory()
{
}

CreateObj.h  这是增加易用性宏

CREATE_OBJECT提供了模板版本增加类型转换易用性

#ifndef __CREATEOBJ_H__
#define __CREATEOBJ_H__

#include "ObjectFactory.h"

#define DECLARE_DYNAMIC_CREATE(CLASS_NAME) \
    static Object* CreateObj(); \
    std::string GetClassName() const override;

#define DYNAMIC_CREATE(CLASS_NAME) \
    Object* CLASS_NAME::CreateObj() \
    { \
        return static_cast<Object*>(new CLASS_NAME()); \
    } \
    \
    std::string CLASS_NAME::GetClassName() const \
    { \
        return #CLASS_NAME; \
    } \
    \
    static int g_tmp_##CLASS_NAME = \
        ObjectFactory::GetInstance().RegisterObj(#CLASS_NAME, CLASS_NAME::CreateObj);


template<typename T>
T* CREATE_OBJECT(const std::string& className)
{
    return dynamic_cast<T*>(ObjectFactory::GetInstance().CreateObj(className));
}

#endif

测试代码

Person.h 支持动态创建声明DECLARE_DYNAMIC_CREATE

#ifndef __PERSON_H__
#define __PERSON_H__

#include "CreateObj.h"
#include <string>

class Person : public Object
{
public:
    DECLARE_DYNAMIC_CREATE(Person)

    virtual void Do();
    
    void IntroduceSelf();

    std::string name_;
    int age_;
};

#endif

Person.cpp

支持动态创建实现宏 DYNAMIC_CREATE

#include "Person.h"
#include <iostream>
using namespace std;

DYNAMIC_CREATE(Person)

void Person::IntroduceSelf()
{
    cout << "I am "<<name_<<", "<<age_<<" years old"<<endl;
}

void Person::Do()
{
    cout << "Do nothing" << endl;
}

Student.h

#ifndef __STUDENT_H__
#define __STUDENT_H__

#include "Person.h"

class Student : public Person
{
public:
    DECLARE_DYNAMIC_CREATE(Student)

    void Do() override;
};

#endif

Student.cpp

#include "Student.h"
#include "Person.h"
#include <iostream>
using namespace std;

DYNAMIC_CREATE(Student)

void Student::Do()
{
    cout << "I am a student, I am learning" << endl;
}

测试用例

没有引入Student.h, 但可以通过类名字符串"Student"创建实例执行

#include "gtest.h"
#include "Person.h"
#include "CreateObj.h"
#include <vector>
using namespace std;

class CreateObjTest : public ::testing::Test
{
};

void PersonExecute(Person* p)
{
    p->name_="wangliang";
    p->age_ = 18; 
    p->IntroduceSelf();
    p->Do();
}

TEST_F(CreateObjTest, TestCreatePerson) 
{
    Person* p = CREATE_OBJECT<Person>("Person");
    if(p == nullptr)
    {
        GTEST_FAIL();
        return;
    }
    EXPECT_TRUE(p->GetClassName() == "Person");
    PersonExecute(p);
}

TEST_F(CreateObjTest, TestCreateStudentAsPerson) 
{
    Person* p = CREATE_OBJECT<Person>("Student");
    if(p == nullptr)
    {
        GTEST_FAIL();
        return;
    }
    EXPECT_TRUE(p->GetClassName() == "Student");
    PersonExecute(p);
}

运行效果:

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值