回顾前面的文章,实现了一个简单工厂模式来创建不同类对象,但由于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() = 
;

    
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 
;

        
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 
;

}

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

从零开始学C++之动态创建对象的更多相关文章

  1. (43). Spring Boot动态数据源(多数据源自动切换)【从零开始学Spring Boot】

    在上一篇我们介绍了多数据源,但是我们会发现在实际中我们很少直接获取数据源对象进行操作,我们常用的是jdbcTemplate或者是jpa进行操作数据库.那么这一节我们将要介绍怎么进行多数据源动态切换.添 ...

  2. 从零开始学 Web 之 JavaScript(五)面向对象

    大家好,这里是「 Daotin的梦呓 」从零开始学 Web 系列教程.此文首发于「 Daotin的梦呓 」公众号,欢迎大家订阅关注.在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识 ...

  3. 从零开始学 Java - Spring 集成 ActiveMQ 配置(二)

    从上一篇开始说起 上一篇从零开始学 Java - Spring 集成 ActiveMQ 配置(一)文章中讲了我关于消息队列的思考过程,现在这一篇会讲到 ActivMQ 与 Spring 框架的整合配置 ...

  4. 从零开始学 Java - Spring 一主多从、多主多从 数据库配置

    待会苹果要开发布会 我写完这篇文章就准备去看发布会了,因为我买了好几包瓜子和啤酒.由于苹果的保密做的越来越差劲,该曝光的信息差不多全部曝光了,我们这种熬夜看发布会的只不过是让这些信息更加真实,或者说是 ...

  5. 从零开始学 Java - Spring AOP 实现主从读写分离

    深刻讨论为什么要读写分离? 为了服务器承载更多的用户?提升了网站的响应速度?分摊数据库服务器的压力?就是为了双机热备又不想浪费备份服务器?上面这些回答,我认为都不是错误的,但也都不是完全正确的.「读写 ...

  6. 从零开始学Bootstrap(2)

    继从零开始学Bootstrap(1)后,我们需要实际做一些页面,边学边做.因为前端是一项非常注意实践的技术,知识点太多.太琐碎了,所以我们只能边学边做.根据我们想要做的效果,去查相应的资料.不要想着把 ...

  7. 从零开始学Sketch——进阶篇-b

    从零开始学Sketch——进阶篇 Sketch是一款矢量绘图应用,而矢量绘图无疑是目前进行网页.图标以及界面设计的最好方式. 在初识了Sketch的界面布局和基础工具之后,我们就可以开始进入高阶的Sk ...

  8. 57. Spring 自定义properties升级篇【从零开始学Spring Boot】

    之前在两篇文章中都有简单介绍或者提到过 自定义属性的用法: 25.Spring Boot使用自定义的properties[从零开始学Spring Boot] 51. spring boot属性文件之多 ...

  9. 从零开始学 Web 系列教程

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新…… github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:http:/ ...

随机推荐

  1. CCIE路由实验(9) -- IPv6

    1.IPv6地址的各种情况2.配置通过DHCP-PD方式分配前缀信息3.IPv6路由基本配置4.IPv6路由--RIPng5.IPv6路由--EIGRPv66.IPv6路由--OSPFv37.IPv6 ...

  2. NotePad++ 快捷键中文说明

    Ctrl-H 打开Find / Replace 对话框 Ctrl-D 复制当前行 Ctrl-L 删除当前行 Ctrl-T 上下行交换 F3 找下一个 Shift-F3 找上一个 Ctrl-Shift- ...

  3. 增强SEO的div+css命名规则

    页头:header登录条:loginBar标志:logo侧栏:sideBar广告:banner导航:nav子导航:subNav菜单:menu子菜单:subMenu搜索:search滚动:scroll页 ...

  4. ASP.NET - Eval数据绑定

    <!--新闻分类--> <div id ="category" class ="Frm"> <h4>新闻分类</h4& ...

  5. Redis 与 Memcache

    最近,我们看到许多使用Redis的案例,尤其是大型及先进的系统中应用的更多.事实上,我们正管理着一个新的规模庞大的Redis集群,设计该架构是为了每秒能处理上百万个事务.然而,Redis与Memcac ...

  6. 【图像识别】 图像处理和图像分析(leptonica)leptonica-1.68安装配置 (vs2008)

    Leptonica Leptonica is a pedagogically-oriented open source site containing software that is broadly ...

  7. Swift - 发送消息(文本,图片,文件等)给微信好友或分享到朋友圈

    通过调用微信提供的API接口,我们可以很方便的在应用中发送消息给微信好友,或者分享到朋友圈.在微信开发平台(https://open.weixin.qq.com)里,提供了详细的说明文档和样例.但由于 ...

  8. Python金融应用编程(数据分析、定价与量化投资)

    近年来,金融领域的量化分析越来越受到理论界与实务界的重视,量化分析的技术也取得了较大的进展,成为备受关注的一个热点领域.所谓金融量化,就是将金融分析理论与计算机编程技术相结合,更为有效的利用现代计算技 ...

  9. uva 129

    暴力求解 大致题意 如果一个字符串含有相邻的重复字串称为容易的串,反之为非容易 求字典序第n困难的串…… 大致思路,暴力如果是容易的串停过,然后困难的串继续求解tot++ 总之先记着吧…… 最后输出格 ...

  10. Hadoop--序列化

    序列化: 对象的序列化用于将一个对象编码成字节流,以及从字节流中重新构建对象. 将一个对象编码成一个字节流称为序列化该对象. 序列化三种主要的用途: 1.作为一种持久化格式. 2.作为一种通信的数据格 ...