189 8069 5689

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

背景

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

创新互联于2013年成立,先为调兵山等服务建站,调兵山等地企业,进行企业商务咨询服务。为调兵山企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
#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#include#includeclass Object
{
public:
    virtual std::string GetClassName() const = 0;
};

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

    using ObjCreator = std::function;
    int RegisterObj(const std::string& className, ObjCreator objCreator);

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

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

    std::mapcreatorMap_;
};

#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(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);


templateT* CREATE_OBJECT(const std::string& className)
{
    return dynamic_cast(ObjectFactory::GetInstance().CreateObj(className));
}

#endif

测试代码

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

#ifndef __PERSON_H__
#define __PERSON_H__

#include "CreateObj.h"
#includeclass 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"
#includeusing namespace std;

DYNAMIC_CREATE(Person)

void Person::IntroduceSelf()
{
    cout<< "I am "<

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"
#includeusing 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"
#includeusing 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");
    if(p == nullptr)
    {
        GTEST_FAIL();
        return;
    }
    EXPECT_TRUE(p->GetClassName() == "Person");
    PersonExecute(p);
}

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

运行效果:

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


分享文章:C++框架技术-根据类名动态创建类对象-创新互联
网站地址:http://jkwzsj.com/article/hjoss.html