C++ 简易string类实现(五)-进一步抽象
来源:互联网 发布:淘宝国际卖家 编辑:程序博客网 时间:2024/06/18 09:55
前四篇所叙述的每一件事情,都必须动用到我们感兴趣的那个class的源代码.但如果我们想要将reference counting施行于程序库中一个名为Widget的class呢?程序库的行为不是我们可以更改的,所以没办法让Widget继承自RCObject,也就无法对Widget使用smart RCPtrs.
但只要稍微修改设计,我们就可以为任何类型加上reference counting能力.
首先,让我们考虑,如果令Widget继承自RCObject,我们的设计看起来将如何.这种情况下,我们必须增加一个RCWidget class给clients使用,但每件事情都极类似先前的String/StringValue例子:RCWidget扮演String角色,Widget扮演StringValue的角色.整个设计看起来去如下:
现在我们可以将”计算机科学领域中大部分问题得以解决”的原理施展出来.我们可以加上一层间接性.是的,我们增加一个新的CountHolder class,用以持有引用次数,并令CountHolder继承自RCObject.我们也令CountHolder内含一个指针,指向一个Widget.然后将smart RCPtr template以同样聪明的RCIPtr template取代,后者知道CountHolder class 的存在.RCIPtr的”I”意指”indirect”(间接).修改后的设计如下:
就像”StringValue只是实现细节,不需要让String的用户知道”一样,CountHolder也是实现细节,不需要让RCWidget的用户知道.事实上,它是RCIPtr的实现细节,所以我们把它嵌套放进RCIPtr class的内部.RCIPtr的声明如下:
template<typename T>class RCIPtr{public: RCIPtr(T* realPtr = nullptr); RCIPtr(const RCIPtr& rhs_); RCIPtr& operator=(const RCIPtr& rhs_); ~RCIPtr();public: const T* operator->() const; T* operator->(); const T& operator*() const; T& operator*();private: void init(); void makeCopy();private: struct CountHolder : public RCObject { T* ptr; ~CountHolder() { if (ptr != nullptr) { delete ptr; ptr = nullptr; } } }; CountHolder* _counter;};
RCIPtr和RCPtr之间存在两个差异.第一,”RCPtr对象”之间指向实值,而”RCIPtr对象”通过中介层”CountHolder”对象指向实值;第二,RCIPtr将operator->和operator*重载了,如此一来,只要有non-const access发生于被指物上,copy-on-write(写时进行复制)就会自动执行.
RCIPtr定义如下:
template<typename T>void RCIPtr<T>::init(){ if (_counter->isShareable() == false) { auto oldptr = _counter->ptr; _counter = new CountHolder(); _counter->ptr = new T(*oldptr); } _counter->addReference();}template<typename T>RCIPtr<T>::RCIPtr(T* realPtr /* = nullptr */) : _counter(new CountHolder()){ _counter->ptr = realPtr; init();}template<typename T>RCIPtr<T>::RCIPtr(const RCIPtr& rhs_) : _counter(rhs_._counter){ init();}template<typename T>RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs_){ if (_counter ! = rhs_._counter) { _counter->removeReference(); _counter = rhs_._counter; init(); } return *this;}template<typename T>RCIPtr<T>::~RCIPtr(){ _counter->removeReference();}template<typename T>const T* RCIPtr<T>::operator->() const{ return _counter->ptr;}template<typename T>T* RCIPtr<T>::operator->(){ makeCopy(); return _counter->ptr;}template<typename T>const T& RCIPtr<T>::operator*() const{ return *(_counter->ptr);}template<typename T>T& RCIPtr<T>::operator*(){ makeCopy(); return *(_counter->ptr);}template<typename T>void RCIPtr<T>::makeCopy(){ if (_counter->isShared()) { auto oldptr = _counter->ptr; _counter->removeReference(); _counter = new CountHolder(); _counter->ptr = new T(*oldptr); _counter->addReference(); }}
有了RCIPtr,RCWidget的实现就很容易了,因为RCWidget的每一个函数都只是通过底层的RCIPtr转调对应的Widget函数.示例如下:
class Widget{public: void doThis() { std::cout << "doThis" << std::endl; }};class RCWidget{public: void doThis() { _value->doThis(); }private: RCIPtr<Widget> _value;};
对于String类,我们只需要将C++ 简易string类实现(一)参考上述Widget和RCWidget的例子,生成一个对应的RCString就OK了;
小结:通过不断的抽象,最终将引用计数类和用户自定义类完全解耦,而且引用计数类还可以重用于其它用户自定义类,简直 完美!!!
完整代码如下:
class RCObject{public: RCObject(); RCObject(const RCObject& rhs_); //使RCObject成为抽象基类,但该纯虚函数需要提供 //定义,不然会使被继承的类无法在栈上创建(原因可 //查阅如何仅在堆上或栈上分配内存) virtual ~RCObject() = 0; public: void addReference(); void removeReference(); void markUnshareable(); bool isShareable() const; bool isShared() const;private: RCObject& operator=(const RCObject&) = delete;private: int refCount; bool shareable;};template<typename T>class RCIPtr{public: RCIPtr(T* realPtr = nullptr); RCIPtr(const RCIPtr& rhs_); RCIPtr& operator=(const RCIPtr& rhs_); ~RCIPtr();public: const T* operator->() const; T* operator->(); const T& operator*() const; T& operator*();private: void init(); void makeCopy();private: struct CountHolder : public RCObject { T* ptr; ~CountHolder() { if (ptr != nullptr) { delete ptr; ptr = nullptr; } } }; CountHolder* _counter;};
RCObject::RCObject() :refCount(0), shareable(true) //refCount初始化为0,其值完全有RCPtr控制{}RCObject::RCObject(const RCObject&)//调用无参构造函数,注意:该调用仅能在//初始化成员列表里,如果在函数实现内调用,//那么仅仅是在栈上生成新的对象,而不是完成//该对象的成员初始化 :RCObject(){ std::cout << "RCObject" << std::endl;}RCObject::~RCObject(){ //std::cout << "~RCObject" << std::endl;}void RCObject::addReference(){ ++refCount;}void RCObject::removeReference(){ if (--refCount == 0) { delete this; }}void RCObject::markUnshareable(){ shareable = false;}bool RCObject::isShareable() const{ return shareable;}bool RCObject::isShared() const{ return refCount > 1;}template<typename T>void RCIPtr<T>::init(){ if (_counter->isShareable() == false) { auto oldptr = _counter->ptr; _counter = new CountHolder(); _counter->ptr = new T(*oldptr); } _counter->addReference();}template<typename T>RCIPtr<T>::RCIPtr(T* realPtr /* = nullptr */) : _counter(new CountHolder()){ _counter->ptr = realPtr; init();}template<typename T>RCIPtr<T>::RCIPtr(const RCIPtr& rhs_) : _counter(rhs_._counter){ init();}template<typename T>RCIPtr<T>& RCIPtr<T>::operator=(const RCIPtr& rhs_){ if (_counter ! = rhs_._counter) { _counter->removeReference(); _counter = rhs_._counter; init(); } return *this;}template<typename T>RCIPtr<T>::~RCIPtr(){ _counter->removeReference();}template<typename T>const T* RCIPtr<T>::operator->() const{ return _counter->ptr;}template<typename T>T* RCIPtr<T>::operator->(){ makeCopy(); return _counter->ptr;}template<typename T>const T& RCIPtr<T>::operator*() const{ return *(_counter->ptr);}template<typename T>T& RCIPtr<T>::operator*(){ makeCopy(); return *(_counter->ptr);}template<typename T>void RCIPtr<T>::makeCopy(){ if (_counter->isShared()) { auto oldptr = _counter->ptr; _counter->removeReference(); _counter = new CountHolder(); _counter->ptr = new T(*oldptr); _counter->addReference(); }}
- C++ 简易string类实现(五)-进一步抽象
- C++ 简易string类实现(一)
- 抽象类的进一步使用
- C++ 简易string类实现(二)-引用计数
- String类的简易实现(C++语言)
- C++ String简易实现
- 【C/C++】String类实现
- String类的进一步学习一
- String类的进一步学习二
- c简易实现数据库
- 抽象类(C++)
- C++ 简易string类实现(三)-抽离引用计数
- C++ 简易string类实现(四)-自动操作引用次数
- C++ 简易string类实现(六)-真正的写时复制
- Effective C++(五)实现
- 抽象工厂模式 (C语言实现)
- [C++]String类的实现
- [C++]String类的实现
- 0517
- 字符串转换成十进制整数
- vivo2017实习生编程题
- Python:Template使用指南
- Java List集合使用方法介绍(2)——公告管理
- C++ 简易string类实现(五)-进一步抽象
- 多路查找树(B树)
- Linux中软链接和硬链接的区别(笔记)
- 台湾大学林轩田机器学习基石课程学习笔记11 -- Linear Models for Classification
- 人员签到程序
- 宏润年
- undefined和null的区别
- 用java解决大数
- BZOJ 4893 项链分赃