从零开始学C++之动态创建对象

回顾前面的文章,实现了一个简单工厂模式来创建不同类对象,但由于c++没有类似new "Circle"之类的语法,导致CreateShape 函数中需要不断地ifelse地去判断,如果有多个不同类对象需要创建,显然这是很费神的,下面通过宏定义注册的方法来实现动态创建对象。

Shape.h:

#ifndef _SHAPE_H_
#define _SHAPE_H_

class Shape
{
public:
    virtual void Draw() = 0;
    virtual ~Shape() {}
};

class Circle : public Shape
{
public:
    void Draw();
    ~Circle();
};

class Square : public Shape
{
public:
    void Draw();
    ~Square();
};

class Rectangle : public Shape
{
public:
    void Draw();
    ~Rectangle();
};

#endif // _SHAPE_H_

Shape.cpp:

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


void Circle::Draw()
{
    cout << "Circle::Draw() ..." << endl;
}
Circle::~Circle()
{
    cout << "~Circle ..." << endl;
}

void Square::Draw()
{
    cout << "Square::Draw() ..." << endl;
}
Square::~Square()
{
    cout << "~Square ..." << endl;
}

void Rectangle::Draw()
{
    cout << "Rectangle::Draw() ..." << endl;
}

Rectangle::~Rectangle()
{
    cout << "~Rectangle ..." << endl;
}

REGISTER_CLASS(Circle);
REGISTER_CLASS(Square);
REGISTER_CLASS(Rectangle);

DynBase.h:

#ifndef _DYN_BASE_H_
#define _DYN_BASE_H_

#include <map>
#include <string>
using namespace std;

typedef void *(*CREATE_FUNC)();

class DynObjectFactory
{
public:
    static void *CreateObject(const string &name)
    {
        map<string, CREATE_FUNC>::const_iterator it;
        it = mapCls_.find(name);
        if (it == mapCls_.end())
            return 0;
        else
            return it->second(); //func();

    }

    static void Register(const string &name, CREATE_FUNC func)
    {
        mapCls_[name] = func;
    }
private:
    static map<string, CREATE_FUNC> mapCls_;
};

// g++
// __attribute ((weak))
__declspec(selectany) map<string, CREATE_FUNC> DynObjectFactory::mapCls_;
//头文件被包含多次,也只定义一次mapCls_;

class Register
{
public:
    Register(const string &name, CREATE_FUNC func)
    {
        DynObjectFactory::Register(name, func);
    }
};

#define REGISTER_CLASS(class_name) \
class class_name##Register { \
public: \
    static void* NewInstance() \
    { \
        return new class_name; \
    } \
private: \
    static Register reg_; \
}; \
Register class_name##Register::reg_(#class_name, class_name##Register::NewInstance)
//CircleRegister

#endif // _DYN_BASE_H_

DynTest.cpp:

#include "Shape.h"
#include "DynBase.h"
#include <iostream>
#include <vector>
#include <string>
using namespace std;



void DrawAllShapes(const vector<Shape *> &v)
{
    vector<Shape *>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        (*it)->Draw();
    }
}

void DeleteAllShapes(const vector<Shape *> &v)
{
    vector<Shape *>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        delete(*it);
    }
}


int main(void)
{
    vector<Shape *> v;

    Shape *ps;
    ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Circle"));
    v.push_back(ps);
    ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Square"));
    v.push_back(ps);
    ps = static_cast<Shape *>(DynObjectFactory::CreateObject("Rectangle"));
    v.push_back(ps);

    DrawAllShapes(v);
    DeleteAllShapes(v);


    return 0;
}

在DynBase.h 中#define了一个宏定义REGISTER_CLASS(class_name),且在Shape.cpp 中调用宏定义,拿REGISTER_CLASS(Circle);

来说,程序编译预处理阶段会被替换成:

class CircleRegister {  public: 

static void* NewInstance()  { 

return new Circle; 

private: 

static Register reg_; 

};  Register CircleRegister::reg_("Circle",CircleRegister::NewInstance);

也即定义了一个新类,且由于含有static 成员,则在main函数执行前先执行初始化,调用Register类构造函数,在构造函数中调用DynObjectFactory::Register(name, func); 即调用DynObjectFactory 类的静态成员函数,在Register函数中通过map容器完成了字符串与函数指针配对的注册,如mapCls_[name] = func;

进入main函数,调用DynObjectFactory::CreateObject("Circle") ,CreateObject函数中通过string找到对应的函数指针(NewInstance),并且调用后返回创建的对象指针,需要注意的是 return it->second(); 中it->second 是函数指针,后面加括号表示调用这个函数。对宏定义中的#,##用法不熟悉的可以参考这里

这样当需要创建多个不同类对象的时候,就不再需要写很多ifelse的判断了。

参考:

C++ primer 第四版 Effective C++ 3rd C++编程规范

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

7356
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

5258
来自专栏码匠的流水账

聊聊NettyConnector的start及shutdown

reactor-netty-0.7.6.RELEASE-sources.jar!/reactor/ipc/netty/NettyConnector.java

1031
来自专栏一个爱瞎折腾的程序猿

sqlserver使用存储过程跟踪SQL

USE [master] GO /****** Object: StoredProcedure [dbo].[sp_perfworkload_trace_s...

3000
来自专栏hbbliyong

WPF Trigger for IsSelected in a DataTemplate for ListBox items

<DataTemplate DataType="{x:Type vm:HeaderSlugViewModel}"> <vw:HeaderSlug...

4224
来自专栏张善友的专栏

LINQ via C# 系列文章

LINQ via C# Recently I am giving a series of talk on LINQ. the name “LINQ via C...

3025
来自专栏芋道源码1024

熔断器 Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker

本文主要基于 Hystrix 1.5.X 版本 1. 概述 2. HystrixCircuitBreaker 3. HystrixCircuitBreaker....

5827
来自专栏飞扬的花生

jsencrypt参数前端加密c#解密

      写程序时一般是通过form表单或者ajax方式将参数提交到服务器进行验证,如何防止提交的请求不被抓包后串改,虽然无法说绝对安全却给非法提交提高了难度...

4239
来自专栏张善友的专栏

Mix 10 上的asp.net mvc 2的相关Session

Beyond File | New Company: From Cheesy Sample to Social Platform Scott Hansel...

2787
来自专栏跟着阿笨一起玩NET

c#实现打印功能

3832

扫码关注云+社区