回顾前面的文章,实现了一个简单工厂模式来创建不同类对象,但由于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. URAL 1180. Stone Game (博弈 + 规律)

    1180. Stone Game Time limit: 1.0 second Memory limit: 64 MB Two Nikifors play a funny game. There is ...

  2. IMAP和POP3有什么差别?

    servCode=6010376">POP3协议同意电子邮件client下载server上的邮件,可是在client的操作(如移动邮件.标记已读等),不会反馈到server上.比方通过 ...

  3. 11g r2 模拟OCR和voting disk不可用,完整恢复过程,以及一些注意事项

    环境:RHEL5.8 RAC 11.2.0.3.0 1:查看ORC和voting disk信息: In 11g Release 2 your voting disk data is automatic ...

  4. Linux下mpi环境配置与执行步骤(Ubuntu为例)

    转载注明出处: http://blog.csdn.net/bendanban/article/details/9136755 以两台计算机为例,将这两台计算机应用于MPI运行环境. 第一步:在两台机器 ...

  5. 跨服务器查询sql (摘要)

    首先推荐一个神作:http://www.cnblogs.com/daniel206/archive/2008/01/16/1041748.html 大神比较详细了.而且条理很清晰. 然后摘录一些其他的 ...

  6. HTTP协议--简析

    HTTP--超文本传输协议(HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议,是所有的www文件都必须遵守的标准. 要想成为优秀的web开发人员,必须熟悉H ...

  7. (转载)QT中PRO文件写法的详细介绍,很有用,很重要!

    版权声明:本文为博主原创文章,未经博主允许不得转载. 在QT中,有一个工具qmake可以生成一个makefile文件,它是由.pro文件生成而来的,.pro文件的写法如下: 1. 注释从“#”开始,到 ...

  8. 【AllJoyn专题】基于AllJoyn和Yeelink的传感器数据上传与指令下行的研究

    接触高通物联网框架AllJoyn不太久,但确是被深深地吸引了.在我看来,促进我深入学习的原因有三点:一.AllJoyn开源,对开源的软硬件总会有种莫名的喜爱,虽然或许不会都深入下去:二.顺应潮流,物联 ...

  9. swift-var/let定义变量和常量

    // Playground - noun: a place where people can play import UIKit //--------------------------------- ...

  10. Swift - 使用相机拍摄照片

    1,打开相机拍照 通过设置图片控制器UIImagePickerController的来源为UIImagePickerControllerSourceType.Camera,便可以打开相机 1 2 3 ...