c++代理类(二)

2. 智能指针

 “c++代理类(一)”中完成的简单代理类虽然解决了最急迫的问题,但效率上又存在了另外的问题,该简单类存在的问题主要是:

每个代理类对象都唯一关联一个实际对象,代理类对象存在则实际对象存在,代理类对象释放则实际类对象也要释放,且复制代理类对象就必须要复制实际类对象。这在实际类很大的时候复制开销是非常大的。而且,代理类的复制会频繁的发生,比如:作为函数的参数进行值传递,或者作为函数的返回值等等。

我们将对该简单代理类进行改进,改进的思想主要是:在代理类中为其代理的实际对象添加一个标记,该标记指出有多少个代理类对象代理了这个实际对象,这样当我们复制代理类对象时,其实际所代理的对象就不需要复制了,只需要修改该标记即可。

其具体做法如下:

class VehicleSurrogate
{
public:
        ......//跟简单类一样,唯一不同的是需要加入处理标记num的部分
private:
    Vehicle* vp;
    int * num; //添加的标记字段
};
有了如上的结构,每次复制代理类时,只需要将(*num)++就可以了。其意义为:绑定到实际对象的代理类又多了一个

上述的策略在不需要修改实际对象时非常有用,即所有代理类对象只是读它所代理的实际对象时,但当某个代理类需要修改它所代理的实际对象时,问题就发生了,由于所有代理类对象实际所代理的对象在内存中是同一份,因此,一个代理类对象所做的修改将会影响其他代理类,因此,此时需要对所代理的实际对象进行复制,且该复制是无法避免的。我们称之为——写时复制。

实现指针的类代码如下:

#include <iostream>
using namespace std;

class Vehicle
{
public:
    Vehicle():weight(0.0){} //默认构造函数
    Vehicle(double w):weight(w){} 

    virtual ~Vehicle(){}    //虚析构函数必须存在,因此所有子类对象在析构时都是以Vehicle*的方式调用析构函数的,以虚析构函数调用才能保证调用到正确的析构函数                            //才不会导致内存泄露
    virtual Vehicle* copy()const  //复制自己
    {
        return new Vehicle(*this);
    }

    //读
    double get_weight()const     
    {
        return weight;
    }
    //写
    Vehicle* set_weight(double w)
    {
        weight = w;
        return this;
    }
private:
    double weight; 
};
//定义陆地上的车辆
class RoadVehicle:public Vehicle
{
public:
    RoadVehicle(){} //默认构造函数,容许声明RoadVehicle的数组
    RoadVehicle(double w):Vehicle(w){}
    RoadVehicle(const RoadVehicle& RV):Vehicle(RV.get_weight()){} //拷贝构造函数

    Vehicle* copy()const   //复制自己
    {
        return new RoadVehicle(*this);
    }
    ~RoadVehicle(){}
};
//定义飞机
class AirCraft:public Vehicle
{
public:
    AirCraft(){} //默认构造函数,容许声明AirCraft的数组
    AirCraft(double w):Vehicle(w){}
    AirCraft(const AirCraft& AC):Vehicle(AC.get_weight()){} //拷贝构造函数

    Vehicle* copy()const
    {
        return new AirCraft(*this);
    }
    ~AirCraft(){}
};
//智能指针类定义
class VehicleSurrogate
{
public:
    VehicleSurrogate():vp(new Vehicle()),num(new int(1)){} //默认构造函数,使得可以声明VehicleSurrogate的数组
    VehicleSurrogate(const VehicleSurrogate& VS):vp(VS.vp),num(VS.num)//拷贝构造函数,可发现此时它所代理的实际对象并未复制
    {
        ++(*num);
    }
    VehicleSurrogate(const Vehicle& V):vp(V.copy()),num(new int(1)){}//以它所代理的Vehicle对象初始化
    VehicleSurrogate& operator=(const VehicleSurrogate& VS)//重载赋值,可发现此时它所代理的实际对象并未复制
    {
        if(this != &VS)
        {
            //删除原来的旧的关联对象
            if(--(*num) == 0 )
            {
                delete vp;
                delete num;
            }
            //赋值新的关联对象
            vp = VS.vp;
            num = VS.num;

            ++(*num);
        }
        return *this;
    }
    ~VehicleSurrogate()
    {
        if(--(*num)== 0)
            {
                delete vp;
                delete num;
            }
    }

    int get_num()const
    {
        return *num;
    }
    //代理Vehicle类行为的函数,读操作无需复制所代理的实际对象
    double get_weight()const
    {
        return vp->get_weight();
    }
    //写时复制策略,写时必须复制所代理的实际对象
    VehicleSurrogate& set_weight(double w)
    {
            if((*num) == 1)
            {
                vp->set_weight(w);
            }
            else
            {
                --(*num);

                vp = vp->copy();//真正的复制发生在这里
                num = new int(1);

                vp->set_weight(w);
            }
        return *this;
    }

private:
    Vehicle* vp;
    int * num;
};

int main()
{
   //测试上述智能指针
    VehicleSurrogate parking_lot[100];
    RoadVehicle x(10);
    parking_lot[0] = RoadVehicle(x);
    parking_lot[1] = parking_lot[0];
    parking_lot[0].set_weight(5.0);
    cout << parking_lot[0].get_weight()<<endl<<parking_lot[0].get_num()<<endl;
    cout << parking_lot[1].get_weight()<<endl<<parking_lot[1].get_num()<<endl;
}

使用智能指针,既保留了简单代理类的优点:无需显示管理内存分配,且能实现所代理的实际对象动态绑定,又省略了过多的复制开销。





  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值