c++ 沉思录---代理类
一、问题
如何设计一容器能包含彼此不同而又相互关联的类的对象(处于完整的继承层次的类)?因为一般的数组容器都只能包含一种类型的对象。
假设有一个表示不同类型的交通工具的类的派生层次:
class Vehicle
{
public:
virtual double weight () const = ;
virtual void start() = ;
//.....
}; class RoadVehicle : public Vehicle
{
public:
/* data */
}; class AutoVehivle : public Vehicle
{
public:
/* data */
}; class Aircraft : public Vehicle
{
public:
/* data */
};
现在我们需要一个容器,这里使用数组表示,能够包含所有上述类的对象,Vehicle parkint_lot[100]; 这样肯定不对
错误原因:1. Vehicle 是个抽象基类(含有纯虚函数),不能实例化对象
2. 假设Vehicle能够实例化也不对,Parking_lot[num_vehicles++] = 派生类对象,这样的操作,会将派生类对象转化为一个Vehicle类的对象,会丢失所有Vehicle类中没有的成员。最后的结果是Parking_lot是Vehicle的集合。
二、解决方案1(传统的解决方法)
通过在数组中存储基类的指针,因为基类的指针转换为派生类的指针是容易且安全的。
Vehicle* Parking_lot[100];
然后输入类似:
Automonbile x =
1: Parking_lot[num_vehicles++] = &x;
存在问题:如果x是局部变量,一旦变量x销毁了,Parking_lot 就不知道指向什么东西了。
2: Parking_lot[num_vehicles++] = new Automobile(x);
存在问题:为了解决1中问题,改用存储对象副本的指针。这种方法会带来一定的内存管理负担,其实我觉得还行,没那么严重,在需求没那么严格的情况下这种方法还是可以使用的。
但是,这种只有当我们确定知道要放入parking_lot对象的静态类型后,才启作用!!!
注意:用基类的指针或引用引用一个派生类对象时,由于派生类对象也是基类的对象,所以这样也是安全的但是只能引用基类中所拥有的成员,不能引用在派生类中定义的成员,否则编译器会报错。
三、解决方案2(代理类)
代理类:定义一个行为和Vehicle对象相似,而又潜在的表示为所有继承自Vehicle类的对象的东西,我们把这种类的对象称之为代理。
在Vehicle类中添加虚复制函数
virtual Vehicle* copy() const = 0;
派生类中实现:
Vehicle* 派生类名称::copy() const{
return new 派生类名称(*this);
}
class VehicleSurrogate
{
public:
VehicleSurrogate();
~VehicleSurrogate();
VehicleSurrogate(const Vehicle& v){
vp(v.copy());
} VehicleSurrogate(const VehicleSurrogate&);
VehicleSurrogate& operator = (const VehicleSurrogate&);
private:
Vehicle* vp;
};
代理类的成员变量为Vehivle 类型的指针,参数为const Vehicle& 类型的构造函数,可以为任意继承自Vehicle的类的对象创建代理。
使用方法:
VehicleSurrogate paking_lot[100];
Automobile x;
Paking_lot[num_vehicles++] = x; 等价于 paking_lot[num_vehicles++] = VehicleSurrogate(x);
c++ 沉思录---代理类的更多相关文章
- 【C++沉思录】代理类
1.考虑下面的场景:设计一个容器,包含一组类型不同但相互关联的对象(比如:Animal,Dog,Cat),对象具备多态行为.2.容器一般只能包含一种类型的对象,使用vector<Animal&g ...
- c++沉思录 学习笔记 第五章 代理类
Vehicle 一个车辆的虚基类 class Vehicle {public: virtual double weight()const = 0; virtual void start() = 0; ...
- OOD沉思录 --- 面向动作与面向对象 --- 避免泛滥成灾的类
3.7 从设计中取出不需要的类 只有Get/Set方法的类不算是一个必要的类,Get/Set方法也不算是有意义的行为.这种类降级为属性更加合适. 3.8 去除系统外部的类 如果一个类只调用系统领域的方 ...
- 【C++沉思录】句柄1
1.在[C++沉思录]代理类中,使用了代理类,存在问题: a.代理复制,每次创建一个副本,这个开销有可能很大 b.有些对象不能轻易创建副本,比如文件2.怎么解决这个问题? 使用引用计数句柄,对动态资源 ...
- 生活沉思录 via 哲理小故事
本文转载:http://www.cnblogs.com/willick/p/3174803.html 1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛, ...
- 生活沉思录 via 哲理小故事(一)
1.小托蒂的悲剧 意大利小男孩托蒂,有一只十分奇怪的眼睛,因为从生理上看,这是一只完全正常的眼睛,但却是失明的. 原来,托蒂刚出生时,这只眼睛轻度感染,曾用绷带缠了两个星期.这对常人来说几乎没有人任何 ...
- vs2013 手动生成webservice代理类wsdl
第一步: 第二步: 第三步: 至此wsdl代理类生成成功!
- Struts2 源码分析——Action代理类的工作
章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...
- iOS Class 使用NSProxy和NSObject设计代理类的差异
经常发现在一些需要使用消息转发而创建代理类时, 不同的程序员都有着不同的使用方法, 有些采用继承于NSObject, 而有一些采用继承自NSProxy. 二者都是Foundation框架中的基类, 并 ...
随机推荐
- 分析SQL Server Profiler的监控方式
记得某次给一家公司调优的时候,负责人发给我一堆业务的T-SQL脚本,我面对海量脚本还是从容,虽然不了解内部复杂的业务,但是我们得专注问题的关键 “慢”,我们根据查询的“慢”把他们筛选出来,一一调式优化 ...
- webservice需要的包以及demo
包地址:http://pan.baidu.com/s/1qWyPgqo demo:http://pan.baidu.com/s/1dDvNJg9
- TSQL--聚合函数
--======================================================== --COUNT --COUNT(1) 和COUNT(*) 计算结果相同,COUNT ...
- Angularjs 实现页面遮罩层功能
实现效果: 1.loading指令: "use strict" /** * Created by yw on 2015/9/27. * user defined loading d ...
- solr-DIH:dataimport增量全量创建索引
索引创建完毕,就要考虑怎么定时的去重建, 除了写solrj,可以定时调用下面两条url进行增量或者全量创建索引 全量:http://ip:port/webapp_name/core_name/da ...
- 【node错误】/usr/bin/env: node: No such file or directory
背景 安装了node后,执行npm run xxx的命令的时候,报错,提示如下: /usr/bin/env: node: No such file or directory 步骤 1. 什么玩意,执行 ...
- easyui 导出 excel
<div style="margin-bottom:5px" id="tb"> <a href="#" class=&qu ...
- C#设计模式(23种模式)
https://www.cnblogs.com/abcdwxc/archive/2007/10/30/942834.html
- NOIP2013PUZZLE
#include<cstdio> #include<cstring> #define MIN(A,B) (A)<(B)?(A):(B) using namespace s ...
- Linux基础命令(一)
Linux语法命令 [选项] 参数注意:[]内容是对命令的扩张1.命令中单词之间空格隔开2.单行命令最多256个字符3.大小写区分 clear 清屏pwd 查看当前目录cd 切换目录 .表示当前 ...