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

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

///2013.1.20

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

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

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

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

照一照点心,

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

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

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

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

UML图表示:

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

从表面上看,

与其说是一个模式,

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

然而,

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

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

——深拷贝与浅拷贝。

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

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

一般情况下,

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

&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;

}

输出结果:

0818b9ca8b590ca3270a3433284dd417.png

【注意事项】

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值