代理类

首先定义三个类:

class Animal{
public:virtual void getName()=0;virtual void clone()=0;
};class Cat:public Animal{
public:void getName(){cout<<"this is Cat"<<endl;}Animal* clone(){return new Cat;}
};class Dog:public Animal{
public:void getName(){cout<<"this is Dog"<<endl;}Animal* clone(){return new Dog;}
};

一个 Animal 基类,两个 Animal 的派生类 Dog,Cat,好了做完这个后,现在想开设一个动物园 Zoo,容纳 50 只动物(即这些猫猫狗狗).于并用一个特定且唯一的 Animal_id 来指向 Zoo 里面的一只动物:

Animal* Zoo[50];
int Animal_id = 0;
/* ... */
Zoo[Animal_id++] = new Car;

在开设动物园中的当我们又一只动物死掉了以后,便需要从 Zoo 中还存活的一只动物进行克隆去取代它的位置:

delete Zoo[DeadAnimal_id];
Zoo[DeadAnimal_id] = Zoo[CloneAnimal_id]->clone();

突然发现开这样一个动物园太累了,于是我们可以请一些员工来照看这些动物,这些员工每一个对应一只动物,然后我们就可以把克隆动物,处理死掉的动物:

class AgentManageAnimal{
public:AgentManageAnimal():an(0){}AgentManageAnimal(Animal& argAn):an(argAn.clone()){}AgentManageAnimal(AgentManageAnimal& argAn):an(argAn.an?argAn.an->clone():0){}~AgentManageAnimal(){delete an;}AgentManageAnimal operator =(const AgentManageAnimal argAn){if(this != &argAn){delete an;an = (argAn.an?argAn.an->clone():0);}return *this;}void getName(){ if(an==0)cout<<"there is no Animal!";elsean->getName();}
public:Animal* an;
};

最后我们看看我们的动物园在请了这些代理照看动物的员后是怎么运作的:

AgentManageAnimal Zoo[50];
int Animal_id = 0;
Cat domi;
//AgentManageAnimal(domi) 代表的是创建一个匿名对象
Zoo[Animal_id++] = AgentManageAnimal(domi);

这样我们便可以便捷的管理动物园了.

整理了下,代理类应该具备的哪些内容.以下表列出:


句柄类

上面介绍了一种叫做代理的类,用于让我们在同一个容器中存储类型不同但是相互关联的对象,这种方法需要为每个对象创建一个代理,并要将这些代理存储在容器中.创建代理将会复制所代理的对象,就像复制代理一样,那么当一个对象非常大或者是一种不能轻易复制的资源的时候,这个代理便无法满足我们的需求了.以下要介绍的句柄类,便可以轻松解决这个问题,并且它允许我们在保持代理的多态行为的同时避免不必要的复制.

句柄一般可以设计为两种样式,一种是数据和引用计数器粘合在一起存放,一种是数据和引用计数器分开存放.如下图:

如何设计句柄类?

数据和引用计数器存放在一起

首先我们定义一个类:

class Cat{
public:Cat(){}Cat(const Cat& argCat):name(argCat.name){}Cat(char* argName){name=argName;}void getName(){cout<<"this is "<<name<<endl;}void changeName(char* newName){name=newName;}
private:string name;
};

一个 Cat 类,现在我们有一个宠物猫店,里面有许多宠物猫而且我们又很多管理员来管理这些猫.然后每个猫脖子上面都挂着一个牌子(这个牌子只适用套在猫的脖子上),上面有一个条形码记录这对应猫和管理这只猫的管理员数量:

class IdCard{
public:friend class Handle;int num;Cat cat;IdCard():num(1){}IdCard(const Cat& argCat):cat(argCat),num(1){}IdCard(char* argName):cat(argName),num(1){}
};

因为出售猫比较赚钱.所以呢我们里面有很雇来的管理员.且一个管理员只照看一只猫,为了让猫时刻都有人照顾所以一只猫可以用多个管理员来照顾,每个管理员手上都有一个与猫脖子上的牌子对应识别器.并且我们在宠物店里面规定,管理员可以给猫换名字,但是管理员在这么做前要先用识别器查看下现在有多少人在管理这只猫,若只要他一人,那么他可以直接给这个猫换名字,但是若管理这只猫的管理员不止他一人,那么他就要去那一只新的猫,然后在给这个猫取名字.这个管理器如下:

class Handle{
public:Handle():card(new IdCard){}Handle(char* argName):card(new IdCard(argName)){}Handle(const Handle& argHandle):card(argHandle.card){card->num++;}Handle(const IdCard& argIdCard):card(new IdCard(argIdCard)){}~Handle(){if(--card->num == 0)delete card;};Handle& operator=(Handle &h){h.card->num ++;if(--card->num == 0)delete card;card = h.card;return *this;}void getName(){card->cat.getName();}void changeName(char* newName){if(card->num != 1){--card->num;card = new IdCard(newName);}card->cat.changeName(newName);}
private:IdCard* card;
};

整理了下,句柄类和计数器类应该具备的哪些内容.以下表列出:

数据和引用计数器不存放在一起

在开了一段宠物店的后,我们的宠物店中不仅仅有猫,并且我们也引进了狗.我们来更新下宠物类:

class Animal{
public:virtual void getName()=0;virtual void changeName(char* newName)=0;virtual Animal* clone()=0;
};class Cat:public Animal{
public:Cat(){}Cat(const Cat& argCat):name(argCat.name){}Cat(char* argName){name=argName;}void getName(){cout<<"the cat is "<<name<<endl;}void changeName(char* newName){name=newName;}Animal* clone(){return new Cat(*this);}
private:string name;
};class Dog:public Animal{
public:Dog(){}Dog(const Dog& argDog):name(argDog.name){}Dog(char* argName){name=argName;}void getName(){cout<<"The dog is "<<name<<endl;}void changeName(char* newName){name=newName;}Animal* clone(){return new Dog(*this);}
private:string name;
};

这时猫脖子上的牌子和识别器就有些不适用了.所以我们更新了了下设备.我们引进了一个可以挂在脖子上的牌子,这个牌子的链子,长度可伸缩.以便可以套在大型犬的脖子上.这个牌子将不再记录着牌子对应的动物是哪只动物了,只记录着这只动物有几个管理员共同照看着:

class IdCard{
private:int* num;
public:IdCard():num(new int(1)){}IdCard(const IdCard& argCard):num(argCard.num){*num++;}~IdCard(){if(only())delete num;}bool only(){return *num == 1;}bool reattach(const IdCard& argCard){++*argCard.num;if(only()){delete num;num = argCard.num;return true;}*num--;num = argCard.num;return false;}bool makeOnly(){if(only())return false;*num--;num = new int(1);return true;}
};

与此牌子和对应的是一个新的识别器,当然需要改名字时候还是一样,管理员在这么做前要先用识别器查看下现在有多少人在管理这只动物,若只要他一人,那么他可以直接给这个动物换名字,但是若管理这只动物的管理员不止他一人,那么他就要去找一只品种一样动物,然后在给这个动物取名字:

class Handle{
public:Handle(Animal* argAnimal):animal(argAnimal->Clone()){}Handle(const Handle& argHandle):animal(argHandle.animal),card(argHandle.card){}~Handle(){if(card.only())delete animal;};Handle& operator=(Handle &h){if(card.reatach(h.card))delete animal;animal = h.animal;return *this;}void getName(){ animal->getName();}void changeName(char* newName){if(card.makeOnly())animal = animal->Clone();animal->changeName(newName);}
private:Animal* animal;IdCard card;
};

整理了下,句柄类和计数器类应该具备的哪些内容.以下表列出:

C++代理类,句柄(智能指针)_C++沉思录笔记相关推荐

  1. 前向声明 智能指针_C++ 指针类中实现 -gt;*

    C++ 的裸指针是提供 ->* 的运算符的.但 C++ 智能指针目前是不提供 ->* 的运算符的.因为实现起来比较麻烦,而且没有必要.本文来实现一个,需要用到 C++17. 这篇文章本身在 ...

  2. c++ 返回智能指针_C++核心指南(17) I.11 禁止使用指针(T*)或引用(T)来转移所有权...

    I.11: 永远不要使用原始指针(T*)或引用(T&)来转移所有权 原因 如果对调用者或被调用者是否拥有对象有任何疑问,就会发生泄漏或过早析构. 示例 考虑: X* compute(args) ...

  3. C++ 模板类与智能指针

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一.实验内容 二.实验过程 1.模板函数 1.1 一般模板函数 1.1 特化模板函数 2.类模板(Queue) 2.1 类 ...

  4. c++ 沉思录笔记——句柄(第一部分)

    句柄:第一部分 前言 代理类可以让我们在一个容器中存储不同类型但相互关联的对象. 这种方法需要为每一个对象创建一个代理,并要将代理存储在容器中. 创建代理将会复制所代理的对象,就像复制代理一样. 怎么 ...

  5. get方法报空指针_智能指针shared_ptr踩坑笔记

    平时写代码一直避免使用指针,但在某些场景下指针的使用还是有必要的.最近在项目中简单使用了一下智能指针(shared_ptr),结果踩了不少坑,差点就爬不出来了.痛定思痛抱着<Cpp Primer ...

  6. c++ 指针_C/C++学习笔记——C提高:指针强化

    指针是一种数据类型 指针变量 指针是一种数据类型,占用内存空间,用来保存内存地址. void test01(){ int* p1 = 0x1234; int*** p2 = 0x1111; print ...

  7. 【c++手记】句柄类智能指针

    很多同学学习c++都会看的一本经典教材<Primer> 而在面向对象里面提及到一种概念-智能指针,而往往同学会出现以下的问题 [问题] 智能指针是不是一种指针? stl里面的智能指针是什么 ...

  8. C++ STL 四种智能指针

    文章目录 0.前言 1.unique_ptr 2.auto_ptr 3.shared_ptr 3.1 shared_ptr 简介 3.2 通过辅助类模拟实现 shared_ptr 4.weak_ptr ...

  9. C++ RCSP智能指针简单实现与应用

    智能指针的实现代码来源博客:<http://blog.csdn.net/to_be_better/article/details/53570910> 修改:添加 get()函数,用以获得原 ...

最新文章

  1. Windows10上编译MXNet源码操作步骤(Python)
  2. jira 配置自签SSL证书windowsAD域
  3. 分段二次插值例题_分段三次插值
  4. 进击的PM:作为产品总监,你需要具备什么样的能力?
  5. php strpbrk,PHP 字符串
  6. Linux x86_64内核中断初始化
  7. 第一章 ArcGIS初识
  8. 错误码:28,错误信息:没有足够的存储空间 解决方法
  9. 通过算法理解,把字符串转换成整形数字
  10. 区块链技术在三角债清收领域的应用思考
  11. 看b站学习Android studio的第一天
  12. 撸免费的oracle cloud服务器并使用脚本自动化部署云服务器
  13. SAP S4 实施 会计科目表的实施方法论
  14. 设顺序表va中的数据元素递增有序。先实现将x插入到顺序表的适当位置上,保存该表的有序性。
  15. 贴片Y1电容和贴片Y2电容简介!
  16. 计算机毕业设计SSM城市道路智能停车管理系统【附源码数据库】
  17. CSDN周赛29题解-订班服、争抢糖豆、走楼梯、打家劫舍
  18. ESP8266及数码管的网络时钟
  19. 数字化转型体系化再认识
  20. 计算机 通信类顶级期刊,计算机电子通信等信息类SCI期刊大全.docx

热门文章

  1. C#中Timer组件用法
  2. ASP.NET 学习历程
  3. 使用 ASP.NET 加密口令
  4. lighttpd+PHP安装
  5. Ubuntu14.04 32位上编译VLC2.2.0源码操作步骤
  6. C/C++中“#”和“##”的作用和用法
  7. Java项目:网上图书商城系统(java+SSM+Jsp+MySQL+Redis+JWT+Shiro+RabbitMQ+EasyUI)
  8. 两个苹果手机怎么传通讯录_苹果手机通讯录丢失怎么恢复?货真价实的通讯录恢复技巧...
  9. java获取ajax上传的文件,Java使用Ajax异步上传文件
  10. 使用sbt编译打包,spark-submit命令提交的详细步骤