// // // // // // // // //

///2013.1.20

// // // // // // // // //

还记得小的时候看哆啦A梦,

里面有一话讲到大雄用一个神奇的工具,

好像是一个灯之类的东西,

照一照点心,

点心就会自动复制到无限多(2^n)。

先不管这是不是一件让人羡慕的事情,

但是这个道具,无意间实现了我们今天所要讲的模式——Prototype。

【核心】使用复制(Clone)代替创建(new)对象。

UML图表示:

从表面上看,

与其说是一个模式,

倒不如说是一种复制行为更为贴切。

然而,

这其中,却隐藏着另一个难以察觉的问题。

它涉及到了对象拷贝的两种方式:

——深拷贝与浅拷贝。

在探讨这个两种拷贝方式的区别之前,

首先要提到&这个运算符:

一般情况下,

它的使用方法与指针类似(但不是相等),

&a表示的是a的引用。

一个最简单的使用方法如下所示:

void changeValue(const int& a)

{

a +=10;

}

int value = 10;

changeValue(value);

printf("%d",value);//输出结果为20

一般函数传递的话,

并不可以直接修改实参的值,

然而我们可以利用传递实参的引用(即其地址)来做到这一点。

那么&这个运算符与Prototype有有什么关系呢?

其实,

在C++中,

即使是我们自定义的类,

也存在着一个看不到的复制构造函数,

它的写法格式如下:

SomeClass(constSomeClass& C)

正因为存在着这个函数,

我们才能够使用如下的方法进行对象之间的直接赋值创建:

SomeClass a;

SomeClass b(a);

这是非常方便的。

但是,

很遗憾,

默认的复制构造函数只是浅拷贝,

不是深拷贝。

二者大致的区别就是:

浅拷贝如果遇到动态变量(例如A类中聚合B类对象),就不能正确工作了,因为它只是将地址的引用传给了另一个对象,并没有另外开辟一段内存。

深拷贝就是从这方面着想,对内存实实在在地进行了第二份拷贝(而不是耍小聪明只是传个引用)。

具体深拷贝与浅拷贝的区别可以看这篇文章:http://blog.csdn.net/bluescorpio/article/details/4322682

因此,

我们实现ProtoType的时候,

最值得注意的地方就是要创建适用于自己类的复制构造函数,

而不仅仅只是使用C++默认的那个。

具体代码实例:

【大致思路】

虚基类Dessert类的两个派生类分别使用了深克隆与浅克隆的方法,可以在他们同样调用copyDessert之后输出的结果中看出来这两种克隆方法的差异。

Dessert.h

#ifndef _DESSERT_H_

#define _DESSERT_H_

class Dessert

{

public:

Dessert(){}

~Dessert(){}

virtual Dessert* copyDessert() = 0;

virtual void outputNum() = 0;

};

class DessertWithDepCopy:public Dessert

{

public:

DessertWithDepCopy();

DessertWithDepCopy(const DessertWithDepCopy& con);

~DessertWithDepCopy();

static int dessertNum;

Dessert* copyDessert();

void outputNum();

};

//Didn't define the copy constructor(Use default).

class DessertWithShallowCopy:public Dessert

{

public:

DessertWithShallowCopy();

~DessertWithShallowCopy();

static int dessertNum;

Dessert* copyDessert();

void outputNum();

};

#endif

Dessert.cpp

#include "Dessert.h"

#include

int DessertWithDepCopy::dessertNum = 0;

int DessertWithShallowCopy::dessertNum = 0;

//DeepCopy class's defination.

DessertWithDepCopy::DessertWithDepCopy()

{

dessertNum++;

}

DessertWithDepCopy::DessertWithDepCopy(const DessertWithDepCopy& con)

{

dessertNum++;

}

DessertWithDepCopy::~DessertWithDepCopy()

{

if(--dessertNum < 0)

dessertNum = 0;

}

Dessert* DessertWithDepCopy::copyDessert()

{

return new DessertWithDepCopy(*this);

}

void DessertWithDepCopy::outputNum()

{

std::cout<

}

//ShallowCopy class's defination.

DessertWithShallowCopy::DessertWithShallowCopy()

{

dessertNum++;

}

DessertWithShallowCopy::~DessertWithShallowCopy()

{

if(--dessertNum < 0)

dessertNum = 0;

}

Dessert* DessertWithShallowCopy::copyDessert()

{

return new DessertWithShallowCopy(*this);

}

void DessertWithShallowCopy::outputNum()

{

std::cout<

}

main.cpp

#include"Dessert.h"

#include

enum

{

Deep,

Shallow

};

int main()

{

Dessert* dessert[2];

dessert[Deep] = new DessertWithDepCopy();

dessert[Shallow] = new DessertWithShallowCopy();

std::cout<

dessert[Deep]->outputNum();

dessert[Shallow]->outputNum();

Dessert* newDessert[2];

//Copy construtor.

newDessert[Deep] = dessert[Deep]->copyDessert();

newDessert[Shallow] = dessert[Shallow]->copyDessert();

std::cout<

dessert[Deep]->outputNum();

dessert[Shallow]->outputNum();

return 0;

}

输出结果:

【注意事项】

如上图所示,在调用copyDessert方法之后,浅克隆的数量却没有增加,但这与我们程序的原有设想是相违背的。

因此,在自己编写的类中,要记得对复制构造函数进行override,从而降低Bug发生概率。

C语言哆啦a梦用printf输出,【2013.1.20】故事的最后,哆啦A梦终于又回到了大雄身边。从此两个人过上了…——ProtoType...相关推荐

  1. printf输出字符串_C语言入门必学第一课,学习“输入与输出”!

    数据输入 编写程序的主要目的就是为了处理数据.数据从哪里来?数据的来源有很多种方式,如从磁盘文件中读取数据.从数据库中读取数据.从网页中抓取数据等,还有一种原始的方式就是从键盘输入数据. 在C语言中, ...

  2. c语言printf输出语句_C语言中另一个printf()语句中的printf()语句

    c语言printf输出语句 A printf() function is a standard library function, that is used to print the text and ...

  3. C语言之printf输出中文乱码

    C语言之printf输出中文乱码 不同编辑器问题解决方案 Clion编辑器 不同编辑器问题解决方案 根据不同的编辑器的表现进行针对性的处理. Clion编辑器 按照以下步骤操作编辑器设置即可: Fil ...

  4. Go语言fmt.Sprintf、fmt.Printf(格式化输出)

    fmt.Printf fmt.Printf在程序中使用%f来格式化所需的值 看起来我们的值被四舍五入到了一个合理的数.但小数点后仍显示了6位,这对我们当前的需要来说实在是太多了. 对于这种情况,格式化 ...

  5. c语言printf输出带符号,输出字符串用什么符号-C语言怎么用printf输出字符串。

    C语言怎么用printf输出字符串. void main() { unsigned char *x = "ab,sdf,sad,23432,cc"; data = x; print ...

  6. c语言用getchar函数输入两个字符c1,c语言:用getchar函数读入两个字符给c1,c2,用putchar和printf输出。思考问题...

    用getchar函数读入两个字符给c1,c2,分别用putchar和printf输出这两个字符.思考以下问题: (1)变量c1和c2定义为字符型还是整型?或二者皆可? (2)要求输出c1和c2的ASC ...

  7. c语言printf输出多个字母,C语言printf嵌套printf然后再嵌套一个printf,嵌套printf输出的疑惑...

    写一个程序,用程序来说明 郁金香Q吧 #include int main( void ) { int i = 1234; printf( "%d", printf( "% ...

  8. c语言对浮点数的处理默认是double吗,C语言中浮点数float和double输出的问题

    C语言中浮点数float和double输出的问题 关注:260  答案:6  信息版本:手机版 解决时间 2019-01-12 07:33 斑駁影 2019-01-11 09:20 #includev ...

  9. C语言 va_start / va_end / va_arg 自定义 printf 函数 - C语言零基础入门教程

    目录 一.前言 二.函数不定长参数简介 1.va_start 2.va_arg 3.va_end 三.win32 控制台版本 四.MFC 对话框版本 五.猜你喜欢 零基础 C/C++ 学习路线推荐 : ...

最新文章

  1. 简单DP【p2642】双子序列最大和
  2. 深入浅出 Redis client/server交互流程
  3. DCMTK:测试ConcatenationCreator类
  4. 存根类 测试代码 java_为旧版代码创建存根-测试技术6
  5. 少儿编程150讲轻松学Scratch(二)-制作过马路小游戏
  6. es6 Reflect对象的静态方法
  7. 【Elasticsearch】 es 排查问题 explain 使用 内容解释
  8. 踩过坑才懂:如何快速打造技术产品
  9. 使用NVivo完善定性编码的艺术
  10. 安装oracle所有依赖包,安装oracle11g R2 缺少依赖包
  11. matlab获取2的整数次幂,如何快速判断正整数是2的N次幂
  12. HiveSql计算占比、同比、占环比
  13. 辐射避难所ol修改服务器数据,辐射避难所ol12月17日数据互通公告
  14. python实现画板_一起看看python+pygame简单画板实现代码实例
  15. $.ajax()方法使用详解
  16. css做名单,css基础教程:2021年适合新手的7个CSS入门教程推荐
  17. jquery easyui iconcls(小图标)属性的设置
  18. windows远程桌面连接使用方法及技巧
  19. 支付系统核心架构设计思路(万能通用)
  20. golang实战-nsq集群入门与坑

热门文章

  1. JS中回调函数的写法
  2. Python数据库字段拆分数据
  3. python列表字典如何提取_怎么提取字典里面的列表里面的字典的value
  4. Linux驱动编程 step-by-step (七) 并发 竞态 (信号量与自旋锁)
  5. Ubuntu安装Sublime Text并输入中文
  6. Laravel 5.2问题-----postman进api的post请求,为什么出现Forbidden?
  7. Java刷题知识点之方法覆盖(方法重写)和方法重载的区别
  8. filter(HTML)滤镜用法
  9. 设计模式(2)策略模式 (模式讲解+应用)
  10. .NET定时任务执行管理器开源组件–FluentScheduler