1、考虑下面的场景:设计一个容器,包含一组类型不同但相互关联的对象(比如:Animal,Dog,Cat),对象具备多态行为。
2、容器一般只能包含一种类型的对象,使用vector<Animal> 会造成对象切割,不具备多态行为。
3、经典的解决办法是:vector<Animal*>, 但是这会增加内存管理的负担。考虑下面的情况:
Dog d;
vec[i] = &d; // 局部对象d销毁, vec[i] 指向垃圾

vec[i] = vec[j]; // 指向同一个对象, 在vec析构之前,需要手动遍历vec,进行delete,两个delete同一个对象,行为未定义。
4、怎么解决上面的问题,每次都创建一个新的对象。如下:
Dog d;
vec[i] = new Dog(d);

vec[i] = new Animal(vec[j]); // 这里存在问题,由于vec[j] 类型未知,只能使用Animal,但是这造成对象切割。
5、处理编译时类型未知的对象,使用虚方法。Animal 增加一个纯虚方法clone,纯虚方法导致Animal成为一个抽象类,
不能实例化,同时要求子类必须重写clone方法。注:Animal 可以提供纯虚方法clone的实现。
6、Animal* pa = new Dog; delete pa; 为了能够调用Dog的析构方法,定义Animal的析构方法是虚方法。注:多态行为要满足两个条件:
方法是虚方法;表面类型和真实类型不一致。
7、有没有更好的办法呢?
使用代理类,对Animal* 管理。也就是栈上对象管理动态资源,利用C++的一个特性,栈上对象离开作用域,必定会调用析构方法,
在析构方法中释放资源。
8、代码如下:
AnimalProxy::AnimalProxy():_pa(NULL)
{

}

AnimalProxy::~AnimalProxy()
{
delete _pa;
}

// 注意:类中可以访问自己的private成员,也可以访问rhs的private成员
AnimalProxy::AnimalProxy(const AnimalProxy& rhs)
{
_pa = (rhs._pa != NULL ? rhs._pa->Clone():NULL);
}

AnimalProxy& AnimalProxy::operator=(const AnimalProxy& rhs)
{
if(this != &rhs) // 等同测试
{
delete _pa; // delete NULL 也没有问题
_pa = (rhs._pa != NULL ? rhs._pa->Clone():NULL); // 指针为NULL判断
}
return *this; // 返回引用
}

AnimalProxy::AnimalProxy(const Animal& animal):_pa(animal.Clone())
{

}

【C++沉思录】代理类的更多相关文章

  1. c++ 沉思录---代理类

    一.问题 如何设计一容器能包含彼此不同而又相互关联的类的对象(处于完整的继承层次的类)?因为一般的数组容器都只能包含一种类型的对象. 假设有一个表示不同类型的交通工具的类的派生层次: class Ve ...

  2. c++沉思录 学习笔记 第五章 代理类

    Vehicle 一个车辆的虚基类 class Vehicle {public: virtual double weight()const = 0; virtual void start() = 0; ...

  3. OOD沉思录 --- 面向动作与面向对象 --- 避免泛滥成灾的类

    3.7 从设计中取出不需要的类 只有Get/Set方法的类不算是一个必要的类,Get/Set方法也不算是有意义的行为.这种类降级为属性更加合适. 3.8 去除系统外部的类 如果一个类只调用系统领域的方 ...

  4. 【C++沉思录】句柄1

    1.在[C++沉思录]代理类中,使用了代理类,存在问题: a.代理复制,每次创建一个副本,这个开销有可能很大 b.有些对象不能轻易创建副本,比如文件2.怎么解决这个问题? 使用引用计数句柄,对动态资源 ...

  5. 生活沉思录 via 哲理小故事

    本文转载:http://www.cnblogs.com/willick/p/3174803.html 1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛, ...

  6. 生活沉思录 via 哲理小故事(一)

    1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛,但却是失明的. 原来,托蒂刚出生时,这只眼睛轻度感染,曾用绷带缠了两个星期.这对常人来说几乎没有人任何 ...

  7. vs2013 手动生成webservice代理类wsdl

    第一步: 第二步: 第三步: 至此wsdl代理类生成成功!

  8. Struts2 源码分析——Action代理类的工作

    章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...

  9. iOS Class 使用NSProxy和NSObject设计代理类的差异

    经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并 ...

随机推荐

  1. (Python)元祖、字典

    本节将学习元组.字典,以及其他涉及到的相关知识 1.元组 (tuple) 元组由圆括号括起来,元素之间用逗号相隔.元组是不可变对象,一旦定义了,就不能更改 >>> t=('a','b ...

  2. [VBS脚本]定时提示并关闭计算机

    一.Natalia.bat 双击这个文件可以运行Natalia 控制台在打开后会变成最小化,标题为PowerAssistant,黑色背景淡绿色文字 运行脚本Natalia.vbs @ECHO OFF ...

  3. php中::的使用方法

    (转载于http://www.nowamagic.net/php/php_UsageOfDoubleColon.php) 双冒号操作符即作用域限定操作符Scope Resolution Operato ...

  4. SQL 修改列名

    exec sp_rename 'student.Ssex','Sex','column'; 执行后就可达到目的. 即是运用了 exec sp_rename '表明.原列名','新列名','column ...

  5. VS 控件命名规范

    基本数据类型 数据类型 数据类型简写 标准命名举例 Array arr arrShoppingList Boolean                         bln blnIsPostBac ...

  6. Subsets 子集系列问题 leetcode

    子集系列问题: Coding 问题中有时会出现这样的问题:给定一个集合,求出这个集合所有的子集(所谓子集,就是包含原集合中的一部分元素的集合). 或者求出满足一定要求的子集,比如子集中元素总和为定值, ...

  7. ReactiveCocoa 5.0 初窥:可能是最痛的一次升级

    RAC 5.0 相比于 4.0 有了巨大的变化,不仅是受 swift 3.0 大升级的影响,RAC 对自身项目结构的也进行了大幅度的调整.这个调整就是将 RAC 拆分为四个库:ReactiveCoco ...

  8. Asp.Net Web API 2第十四课——Content Negotiation(内容协商)

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...

  9. JBoss无规律自动关闭故障定位

    转载地址:http://blog.knowsky.com/264489.htm 最近遇到了几次JBoss无规律自动关闭的奇怪现象,通过history历史命令和last登录信息,都看不到有人操作过的迹象 ...

  10. VPS CentOS-6 下 LNMP HTTP服务器的搭建

    VPS CentOS-6 下 LNMP HTTP服务器的搭建 前言 恢复更新后的第一篇博文, 前段时间由于各种理由, 把博客更新给宕掉了, 个人独立博客的开发也搁浅了, 现在随着工作的逐步稳定, 决心 ...