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


    回顾前面的文章,实现了一个简单工厂模式来创建不同类对象,但由于c++没有类似new "Circle"之类的语法,导致CreateShape 函

    数中需要不断地ifelse地去判断,如果有多个不同类对象需要创建,显然这是很费神的,下面通过宏定义注册的方法来实现动态创

    建对象。


    Shape.h:

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
     
    #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:


     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
    #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:


     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
     
    #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:


     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
     
    #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 newCircle

    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++编程规范


  • 相关阅读:
    【ABAP系列】【第五篇】SAP ABAP7.50 之用户接口
    【ABAP系列】【第六篇】SAP ABAP7.50 之隐式增强
    【ABAP系列】SAP ABAP 带有参数的AMDP的创建
    【MM系列】SAP ABAP 编辑字段出现:对象编辑中的错误
    【ABAP系列】SAP 使用特殊的技术更新数据库(ABAP)
    【ABAP系列】SAP 使用事务码DBCO实现SAP链接外部数据库以及读取例程
    【MM系列】SAP里批量设置采购信息记录删除标记
    【ABAP系列】SAP ABAP如何在调试查看EXPORT/IMPORT 内存数据
    【PP系列】SAP PP模块工作中心主数据维护
    Dom4J
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3188480.html
Copyright © 2020-2023  润新知