回顾前面的文章,实现了一个简单工厂模式来创建不同类对象,但由于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. 基于visual Studio2013解决面试题之1003字符串逆序

     题目

  2. HDU 472 Hamming Distance (随机数)

    Hamming Distance Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) To ...

  3. 用python -i写交互式shell

    cabinet是公司的一个数据存储服务,需要添加一个shell client,查看数据,做简单操作. 用python写了一个比想象的简单.代码如下: #! /usr/bin/python -i # c ...

  4. [转]java开发环境搭建

    分成两个部分: 1.下载安装jdk,并配置环境变量 链接:http://www.runoob.com/java/java-environment-setup.html 2.安装Eclipse 链接:h ...

  5. 在Centos 5.4上安装Mysql5.5.10 (整理以前的工作文档)

    1.     安装环境 1.1.  目的 安装Mysql5.5.10服务,提供公司XXXX测试环境.正式环境也采用该版本的mysql 1.2. 硬件环境 PC机:IntelE5300 内存4G 硬盘5 ...

  6. Eclipse ADT 更换主题

    如果Eclipse 版本3.6以上 在 Help→Eclipse Marketplace 搜索 Theme 之后安装即可 如果Eclipse版本3.5 一下, 通过地址安装插件: http://ecl ...

  7. C++建立动态二维数组

    C++建立动态二维数组主要有两种方法: 1.使用数组指针,分配一个指针数组,将其首地址保存在b中,然后再为指针数组的每个元素分配一个数组                           int * ...

  8. TTL 超时问题

    在TCP/IP网络中,网络层并不对数据包进行可靠性传输保证,只通过ICMP报文提供反馈机制(例如:差错控制).PING命令就是ICMP的请求/响应报文,也是网络最常用的测试手段.通常使用PING命令测 ...

  9. 微凉大大,教你一步一步在linux中正确的安装Xcache加速php。

    首先,强烈吐槽,百度上的教程,都左复制右复制的,乱七八糟,缺东缺西的.借此微凉大大我提供我苦心整理好的教程.以便各位小菜能顺利的使用Xcache加速php,假设看完了,也操作了,还是失败了的话,请联系 ...

  10. [置顶] 强大的JQuery

    JQuery初识 为了简化JS的开发,一些JS库诞生了,JQuery就是其中的一个.JQuery是一个兼容多浏览器的Javascript框架.是轻量级的JS库.jQuery为用户提供了丰富的文档说明, ...