虚拷贝构造技术和property 模式的区别

zrdongjiao 2013-07-29 03:07:21
这是more effective c++中的一个片段:




还有一种特殊种类的虚拟构造函数――虚拟拷贝构造函数――也有着广泛的用途。虚拟拷贝构造函数能返回一个指针,指向调用该函数的对象的新拷贝。因为这种行为特性,虚拟拷贝构造函数的名字一般都是copySelf,cloneSelf或者是象下面这样就叫做clone。很少会有函数能以这么直接的方式实现它:
class NLComponent {
public:
// declaration of virtual copy constructor
virtual NLComponent * clone() const = 0;
...
bbs.theithome.com
};
class TextBlock: public NLComponent {
public:
virtual TextBlock * clone() const // virtual copy
{ return new TextBlock(*this); } // constructor
...
};
class Graphic: public NLComponent {
public:
virtual Graphic * clone() const // virtual copy
{ return new Graphic(*this); } // constructor
...
};
正如我们看到的,类的虚拟拷贝构造函数只是调用它们真正的拷贝构造函数。因此“拷贝”的含义与真正的拷贝构造函数相同。如果真正的拷贝构造函数只做了简单的拷贝,那么虚拟拷贝构造函数也做简单的拷贝。如果真正的拷贝构造函数做了全面的拷贝,那么虚拟拷贝构造函数也做全面的拷贝。如果真正的拷贝构造函数做一些奇特的事情,象引用计数或copy-on-write(参见条款M29),那么虚拟构造函数也这么做。完全一致,太棒了。
注意上述代码的实现利用了最近才被采纳的较宽松的虚拟函数返回值类型规则。被派生类重定义的虚拟函数不用必须与基类的虚拟函数具有一样的返回类型。如果函数的返回类型是一个指向基类的指针(或一个引用),那么派生类的函数可以返回一个指向基类的派生类的指针(或引用)。这不是C++的类型检查上的漏洞,它使得有可能声明象虚拟构造函数这样的函数。这就是为什么TextBlock的clone函数能够返回TextBlock*和Graphic的clone能够返回Graphic*的原因,即使NLComponent的clone返回值类型为NLComponent*。
在NLComponent中的虚拟拷贝构造函数能让实现NewLetter的(正常的)拷贝构造函数变得很容易:
class NewsLetter {
public:
NewsLetter(const NewsLetter& rhs);
...
private:
list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
// 遍历整个rhs链表,使用每个元素的虚拟拷贝构造函数
// 把元素拷贝进这个对象的component链表。
// 有关下面代码如何运行的详细情况,请参见条款M35.
for (list<NLComponent*>::const_iterator it =
rhs.components.begin();
it != rhs.components.end();
++it) {
// "it" 指向rhs.components的当前元素,调用元素的clone函数,
// 得到该元素的一个拷贝,并把该拷贝放到
// 这个对象的component链表的尾端。
components.push_back((*it)->clone());
}
}
如果你对标准模板库(STL)不熟悉,这段代码可能有些令人费解,不过原理很简单:遍历被拷贝的NewsLetter对象中的整个component链表,调用链表内每个元素对象的虚拟构造函数。我们在这里需要一个虚拟构造函数,因为链表中包含指向NLComponent对象的指
bbs.theithome.com
针,但是我们知道其实每一个指针不是指向TextBlock对象就是指向Graphic对象。无论它指向谁,我们都想进行正确的拷贝操作,虚拟构造函数能够为我们做到这点。


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


文章提到的这种 虚拷贝构造函数,我感觉就是propety 模式, propety模式的定义为:

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

学医不精, 感觉2者差不多

...全文
193 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
zrdongjiao 2013-08-03
  • 打赏
  • 举报
回复
引用 6 楼 FENGQIYUNRAN 的回复:
构造函数:是为了“构造”一个对象。(对象之前不存在) 拷贝构造函数:使用一个现成的对象来“构造”另一个对象。(一个对象已经存在,另一个之前不存在) 运算符重载:两个对象都是已经“构造”过的,使用一个对象来重新设置另一个对象。(两个对象都是已经存在的)。
引用 6 楼 FENGQIYUNRAN 的回复:
构造函数:是为了“构造”一个对象。(对象之前不存在) 拷贝构造函数:使用一个现成的对象来“构造”另一个对象。(一个对象已经存在,另一个之前不存在) 运算符重载:两个对象都是已经“构造”过的,使用一个对象来重新设置另一个对象。(两个对象都是已经存在的)。
看第5楼的问题啊,
漫步者、 2013-08-03
  • 打赏
  • 举报
回复
你这个property 模式采用的就是内部复制clone,其实内部接口clone的返回值最好采用多态,与你的抽象接口的返回来行最好保持一致。至于区别:没有。因为他们都是采用的同样的在内部clone他们,保证了封装性,将细节没有透露给用户。
super_admi 2013-08-03
  • 打赏
  • 举报
回复
哇,好多文字啊。 新人前来观望下。
zrdongjiao 2013-08-02
  • 打赏
  • 举报
回复
有人帮忙解答吗?
FeelTouch Labs 2013-08-02
  • 打赏
  • 举报
回复
构造函数:是为了“构造”一个对象。(对象之前不存在) 拷贝构造函数:使用一个现成的对象来“构造”另一个对象。(一个对象已经存在,另一个之前不存在) 运算符重载:两个对象都是已经“构造”过的,使用一个对象来重新设置另一个对象。(两个对象都是已经存在的)。
zrdongjiao 2013-08-02
  • 打赏
  • 举报
回复
引用 4 楼 scumil 的回复:
建议撸主吧代码整理一下,
class NewsLetter {
public:
NewsLetter(const NewsLetter& rhs);
...
private:
list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
// 遍历整个rhs链表,使用每个元素的虚拟拷贝构造函数
// 把元素拷贝进这个对象的component链表。
// 有关下面代码如何运行的详细情况,请参见条款M35.
for (list<NLComponent*>::const_iterator it =
rhs.components.begin();
it != rhs.components.end();
++it) {
// "it" 指向rhs.components的当前元素,调用元素的clone函数,
// 得到该元素的一个拷贝,并把该拷贝放到
// 这个对象的component链表的尾端。
components.push_back((*it)->clone());
}
}
虚拷贝构造技术和property 模式的区别是什么? 我怎么感觉是一样的啊
scumil 2013-08-02
  • 打赏
  • 举报
回复
建议撸主吧代码整理一下,
class NewsLetter {
public:
NewsLetter(const NewsLetter& rhs);
...
private:
list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
// 遍历整个rhs链表,使用每个元素的虚拟拷贝构造函数
// 把元素拷贝进这个对象的component链表。
// 有关下面代码如何运行的详细情况,请参见条款M35.
for (list<NLComponent*>::const_iterator it =
rhs.components.begin();
it != rhs.components.end();
++it) {
// "it" 指向rhs.components的当前元素,调用元素的clone函数,
// 得到该元素的一个拷贝,并把该拷贝放到
// 这个对象的component链表的尾端。
components.push_back((*it)->clone());
}
}
逸萌 2013-08-01
  • 打赏
  • 举报
回复
zrdongjiao 2013-08-01
  • 打赏
  • 举报
回复

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧