什么是C++中的虚拟克隆
作者:bea
又看了一遍more effective c++, 注意到以前没怎么记住的virtual clone技术。 class Base{ public : virtual Base * clone(); }; class Impl1{ public : virtual Impl1 * clone(){ return new Impl1( * this );} }; class Impl2{ public : virtual Impl2 * clone(){
又看了一遍more effective c++, 注意到以前没怎么记住的virtual clone技术。
class Base{
public :
virtual Base * clone();
};
class Impl1{
public :
virtual Impl1 * clone(){ return new Impl1( * this );}
};
class Impl2{
public :
virtual Impl2 * clone(){ return new Impl2( * this; );}
};
public :
Container( const Container & c){
for (List Base *> ::const_iteratorit = c.items.begin();it != c.items.end(); ++ it){
items.push_back( * it -> clone());
}
private :
List Base *> items;
};
这样,每次调用的都是动态类型的clone函数,尽管他们返回的是不同类型,依然具备多态特性。(再扯一句题外话,这里容器里保存指针是很危险的,显然通过拷贝构造的Container对象必须在析构函数里负责delete他们。但是,倘若该Container有其他方式,比如某个push函数,保存指针,那么, container是否有权在析构是删除这些指针就是个问题了。 所以,当容器中不得不使用指针时,还是是最好用shared_ptr或auto_ptr)
Address::create( const sockaddr * name,socklen_tnameLen)
{
MORDOR_ASSERT(name);
Address::ptrresult;
switch (name -> sa_family){
case AF_INET:
result.reset( new IPv4Address());
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
case AF_INET6:
result.reset( new IPv6Address());
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
default :
result.reset( new UnknownAddress(name -> sa_family));
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
}
return result;
}
Address::ptr
Address::clone()
{
return create(name(),nameLen());
}
显然,不足是基类的实现需要涉及所有存在的子类。而且,较真一点,时间效率也是问题。毕竟if else或者switch不如虚指针快。 有用 | 无用
class Base{
public :
virtual Base * clone();
};
class Impl1{
public :
virtual Impl1 * clone(){ return new Impl1( * this );}
};
class Impl2{
public :
virtual Impl2 * clone(){ return new Impl2( * this; );}
};
初一看没什么特别的。clone只是调用了拷贝构造函数。确实,在没有类层次结构的情况下,一个这样的clone()并不会比直接写拷贝构造有用。
奇特的是, 这里3个clone的返回类型是不一样的,但是编译器依然认为后两者是对基类clone()的实现!事实上不只是指针,返回引用也可以达到同样的效果。(题外话,虽然这里clone的语义显然只能返回指针,没人会返回一个局部对象的引用)。
正是由于这种特性,使得以下实现成为可能:
public :
Container( const Container & c){
for (List Base *> ::const_iteratorit = c.items.begin();it != c.items.end(); ++ it){
items.push_back( * it -> clone());
}
private :
List Base *> items;
};
这样,每次调用的都是动态类型的clone函数,尽管他们返回的是不同类型,依然具备多态特性。(再扯一句题外话,这里容器里保存指针是很危险的,显然通过拷贝构造的Container对象必须在析构函数里负责delete他们。但是,倘若该Container有其他方式,比如某个push函数,保存指针,那么, container是否有权在析构是删除这些指针就是个问题了。 所以,当容器中不得不使用指针时,还是是最好用shared_ptr或auto_ptr)
想起昨天在项目代码中也看到了一个clone()的实现。一看竟然没用到虚拟克隆。于是又这样的代码:
Address::create( const sockaddr * name,socklen_tnameLen)
{
MORDOR_ASSERT(name);
Address::ptrresult;
switch (name -> sa_family){
case AF_INET:
result.reset( new IPv4Address());
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
case AF_INET6:
result.reset( new IPv6Address());
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
default :
result.reset( new UnknownAddress(name -> sa_family));
MORDOR_ASSERT(nameLen result -> nameLen());
memcpy(result -> name(),name,nameLen);
break ;
}
return result;
}
Address::ptr
Address::clone()
{
return create(name(),nameLen());
}
显然,不足是基类的实现需要涉及所有存在的子类。而且,较真一点,时间效率也是问题。毕竟if else或者switch不如虚指针快。 有用 | 无用
猜你喜欢
您可能感兴趣的文章:
- 如何使用ASP.NET创建线程
- 如何在VS 2010中调试.NET程序介绍
- C#如何在后台调用Javascript
- 优化ASP.NET性能需要注意的几点
- asp.net实现页面返回代码
- asp.net URL重写实现动态页面静态化
- 采用WebClient 并以post方式发送数据
- FtpWebRequest 实现FTP常用功能详解
- ashx文件和aspx文件有什么区别
- 如何选择website还是web application,哪个好
- asp.net怎样提高首页性能
- 怎样在C#中执行Javascript代码
- 企业市场将是微软的另一条战线
- UML正逐渐下滑的13个理由
- .NET怎样实现 MVC页面返回不同类型的内容
- C#计算文件的MD5值实例
- DateTime日期类型格式化显示
- .NET异常处理最佳实践方案
- 浅谈C++中const类型变量和函数重载