/**
* 书本:【ThinkingInC++】
* 功能:引用计数,可以知道有多少个对象指向这个对象。
* 时间:2014年10月5日14:28:11
* 作者:cutter_point
*/
#include "../require.h" //这个文件是为了检验一些错误的,这个可以用#include<cassert>代替,但是相应的函数也要改
#include <string>
#include <iostream>
using namespace std;
class Dog
{
//私有成员有string的名字,有引用的计数值,构造函数私有化,不让其他外部对象随便生成新的存储空间
//operator=私有化,理由同上,不随便产生新的存储空间
string nm;
int refcount; //用来计数,这个类的引用个数
//这个是构造函数,初始化数据
Dog(const string& name) : nm(name), refcount(1) {cout<<"Creating Dog: "<<*this<<endl;}
//私有的operator=也是避免隐式调用构造函数
Dog& operator = (const Dog& rv);
public:
//然后创建一个Dog对象通过静态方法创建,就是在类开始的地方初始化
static Dog* make(const string& name) {return new Dog(name);}
//拷贝构造函数
Dog(const Dog& d) : nm(d.nm+" copy"), refcount(1) {cout<<"Dog copy-constructor: "<<*this<<endl;}
//析构函数
~Dog() {cout<<"Deleting Dog: "<<*this<<endl;}
//用一个函数来增加一个Dog引用计数,attach
void attach() {++refcount; cout<<"Attached Dog: "<<*this<<endl;}
//一个函数减少引用计数
void detach()
{//减少一个对象引用
require(refcount != 0);
cout<<"Detaching Dog: "<<*this<<endl;
//有条件地删除这个空间
if(--refcount == 0)
delete this;
}
//判定是否引用计数是否为1,就是意味着没有别的对象指向这块内存单元,然后返回this
//如果大于1说明有别的对象指向这个内存单元,那么就复制这块内存单元,创建一个新的内存块
Dog* unalias()
{
cout<<"Unaliasing Dog: "<<*this<<endl;
//如果等于1,那么没有其他对象引用它,直接返回当前对象
if(refcount == 1) return this;
--refcount; //大于1那么就要把原来的对象复制出来一份新的存储空间
return new Dog(*this);
}
//修改名字
void rename(const string& newName)
{
nm=newName;
cout<<"Dog renamed to: "<<*this<<endl;
}
//重载操作符<<输出流
friend ostream& operator << (ostream& os, const Dog& d)
{
return os<<"["<<d.nm<<"], rc = "<<d.refcount;
}
};
class DogHouse
{
Dog* p; //一个指向Dog类的对象
string houseName;
public:
//构造函数,创建一个新的内存
DogHouse(Dog* dog, const string& house) : p(dog), houseName(house) {cout<<"Created DogHouse: "<<*this<<endl;}
//拷贝构造函数
DogHouse(const DogHouse& dh) : p(dh.p), houseName("copy-constructed "+dh.houseName)
{//用一个函数来增加一个Dog引用计数,attach
//拷贝一次吧dh.p的指针赋值给p,没有创建新空间,就是增加了一个引用
p->attach();
cout<<"DogHouse copy-constructor: "<<*this<<endl;
}
//operator=的运算符重载
DogHouse& operator=(const DogHouse& dh)
{
//operator=这里调用了赋值,创建了新的空间,会自动调用了构造函数
//避免自赋值
if(&dh != this)
{
houseName=dh.houseName+" = used";
//所以这里构造函数的时候增加了一个引用在,减少引用,看是否最后一个,没有别的对象在使用它
p->detach();
p=dh.p; //传送指针,给这个对象增加一个引用对象
p->attach(); //增加一个引用
}
cout<<"DogHouse operator= : "<<*this<<endl;
return *this;
}
//析构函数,减少引用
~DogHouse()
{
cout<<"DogHouse destructor: "<<*this<<endl;
p->detach(); //析构一个对象的时候调用这个析构,如果还有对象在引用就不回收空间,如果这是最后个直接回收空间
}
void renameHouse(const string& newName) {houseName=newName;}
//判定是否引用计数是否为1,就是意味着没有别的对象指向这块内存单元,然后返回this
//如果大于1说明有别的对象指向这个内存单元,那么就复制这块内存单元,创建一个新的内存块
void unalias() {p=p->unalias();}
void renameDog(const string& newName) {unalias(); p->rename(newName);}
Dog* getDog() {unalias(); return p;}
friend ostream& operator << (ostream& os, const DogHouse& dh)
{
return os<<"["<<dh.houseName<<"] contains "<<*dh.p;
}
};
int main()
{
DogHouse fidos(Dog::make("Fido"), "FidoHouse"), spots(Dog::make("Spot"), "SpotHouse");
cout<<"开始构造函数"<<endl;
DogHouse bobs(fidos);
cout<<"拷贝构造函数之后"<<endl;
cout<<"fidos:"<<fidos<<endl;
cout<<"spots:"<<spots<<endl;
cout<<"bobs:"<<bobs<<endl;
cout<<"进入赋值运算 spots = fidos"<<endl;
spots=fidos;
cout<<"退出赋值运算 spots = fidos"<<endl;
cout<<"spots:"<<spots<<endl;
cout<<"进入自赋值"<<endl;
bobs=bobs;
cout<<"退出自赋值"<<endl;
cout<<"bobs:"<<bobs<<endl;
cout<<"开始改名字"<<endl;
bobs.getDog()->rename("Bob");
cout<<"退出改名"<<endl;
return 0;
}
大部分注释都是直接写到代码上的,最近感觉自己越来越无知了和自大了!!! 赶紧去学习一下压压惊= =
吓死哥了。