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框架中的基类, 并 ...
随机推荐
- 自我简介与Github的注册和使用
我叫陈鑫,学号1413042059,来自网络工程142班.喜欢打乒乓球,玩策略类游戏,团队竞技. ...
- 10-12Linux流编程的一些知识点
第五章 Linux 的流编程 Linux流操作基础 流和文件的关系:流相当于一个缓冲区,可以将文件描述符和流关联,获得相应的缓冲区,以此来提高系统对磁盘的存取速度. 流的结构和操作 ...
- flask源码解析之DispatcherMiddleware
DispatcherMiddleware作用 实现多app的应用,完成路由分发的功能 如何使用 from werkzeug.wsgi import DispatcherMiddleware from ...
- jzoj3717
#include<bits/stdc++.h> using namespace std; extern int main2(void) __asm__ ("main2" ...
- jzoj5813
tj:可以知道,隨意構造一個數列x,且x的第i位被n整除的方案是(約數個數)^2m,因為所有數可以隨便選,只要這個數能被n整除即可,方案為約數個數 設一個合法數列a的f值為x,則x小於n^m 假設所有 ...
- 编程大牛 Bruce Eckel 对新程序员的忠告
简评:作者 Bruce Eckel 是编程界的大牛,著有大名鼎鼎的<Thinking in C++>和<Thinking in Java>.本文是他对程序员(尤其是新手)的忠告 ...
- [性能分析]linux文件描述符
1.什么是文件和文件描述符 Linux中文件可以分为4种:普通文件.目录文件.链接文件和设备文件.1.普通文件是用户日常使用最多的文件,包括文本文件.shell脚本.二进制的可执行和各种类型的数据.l ...
- C语言奇淫技巧,字符串的三种表示方法,不会用不是合格的程序员
1.在C语言中,是将字符串作为字符数组来处理的,字符串是逐个存放到数组元素中的 例如用一个一维的字符数组存放字符串"I am a boy.",如下代码: char c[12] = ...
- leetcode-73-矩阵置零
题目描述: 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [ [1,1,1], [1,0,1], [1, ...
- SparkSQL开窗函数 row_number()
开始编写我们的统计逻辑,使用row_number()函数 先说明一下,row_number()开窗函数的作用 其实就是给每个分组的数据,按照其排序顺序,打上一个分组内行号 比如说,有一个分组20151 ...