C++里的共享数据

                                                C++里的共享数据

       在这里先提出一个问题,如何将一个类的数据传给另一个类来使用?而且一旦这个类的某些数据改变了,另一个类中的这些数据也能随之改变?

       也许你第一时间就想到了,用全局变量!!!没错,用全局变量可以很方便的解决这个问题,把那些需要传给其他类使用的的数据作为全局变量,因为全局变量只存在一份,所以一旦改变了,全部都会随着改变。

       再来问一个问题,有时候你会想把功能细化,分开几个文件独立完成,那么维护的时候会方便许多,但是问题来了,那些应该需要共享的数据(也就是那些全局变量)应该放在哪里?你也许也会想,将那些全局变量全放到一个文件里,然后其他文件再include就行啦,这样是可以的,但是你不应该只是这些全局变量全放到一个头文件里声明,还得把它的修改者放在实现文件里(即.cpp)文件,也就是会改变这些变量的函数放在实现文件里!为什么?因为这些全局变量的修改值只是在一个cpp文件里有效,其他文件使用的都是它的初值!考虑一下下面的代码,结果会是什么?

//”text.h”

static int i = 0;

void Modify();

//”text.cpp”

#include”text.h”

void Modify()

{

       i= 100;

}

//”main.cpp”

#include”text.h”

void main()

{

       Modify();

       cout<<”i”;

}

你猜结果会是多少?你也许会这样说,这个还用问,当然是100,三岁小孩子都会知道啦!!!当你这样想的时候,赶紧自己去调试一下然后再回答,因为答案会让你吃惊!如果你说是0,那么继续往下看!再考虑下面的代码:

//”text.h”

static int i = 0;

inline void Modify()

{

                     i= 100;

}

//”main.cpp”

#include”text.h”

void main()

{

       Modify();

       cout<<”i”;

}

你也许会疑惑为什么没有text.cpp文件了,因为inline函数必须写在头文件里,那上面的代码会是多少呢?

你也许会这样想,这下我不会上当了,肯定是0,那么恭喜你,又上当了,正确答案是100。因为函数定义多了一个inline,上面的inline函数跟下面的有点像:

void main()

{

       {

              index= 100;

}     

       cout<<”i”;

}

这下你明白为什么是100了吧。那么回到正题,跨多个cpp文件传递全局变量是不行的(我是没办法,不知道你有没有?),除非你把那些改变全局变量的函数全定义为inline,我们知道,这是不合理的!也是不可能的,如果你的函数体太大,inline就不会起作用了。

那还有没有办法呢?你也许会想,把这些需要共享的数据全放到一个基类里,并且声明为static,然后其他要使用的类全继承它,这样确实可以,但不是一个好办法,这样的话,你的派生类得会涨到多大?如果有10个类要使用它,那岂不是得继承10次?如果下面还有-派生呢?这样的结构会非常复杂,难以维护,而且如果基类的东西多了,派生又有自己的,那到时候找个变量都得找半天,而且派生类又不一定会全用上基类的共享数据。

那还有没有更好的办法呢?有,接下来就是主题了,不知道你有没有听过句柄类Handle,或者是智能指针auto_ptr,共享指针share_ptr,这里主要讲一下句柄类,什么是句柄类,如果学过windows编程的话,我们都知道每个窗口都有一个句柄,通过这个句柄,我们就知道要在哪个窗口操作了,要获得编辑框的值,我们也得通过句柄来完成,要修改编辑框的值,也得知道它的句柄。所以它能做到唯一标识的作用,通过这个唯一标识就可以进行修改值,获取值等等,从而实现数据间的对话,何况共享数据呢!!!既然这么强大,那么我们该怎么样使用它呢,不过先来解决我们该怎么定义它呢?下面是它的定义前缀加了一个Jie,那是我名字的最后一个字,只是为了不让跟你Handle混一起而且。当然你的名字最后一个字也是Jie,那很抱歉,我只能做到尽量少的减少名字的污染,不能完全避免。

template <class T>

class JieHandle

{

private:

       T* ptr;

       long*use;

       voidRemoveRef();

public:

       JieHandle(T *p = NULL);

       JieHandle(constJieHandle&);

       ~JieHandle(){RemoveRef();};

       JieHandle& operator=(const JieHandle&);

       T& operator*();

       constT& operator*()const;

       T* operator->();

       const T* operator->()const;

};

template<class T>

inline JieHandle<T>::JieHandle(T *p /* = NULL */)

{

       ptr = p;

       use = newlong(1);

}

template<class T>

inline JieHandle<T>::JieHandle(const JieHandle& h)

{

       ptr = h.ptr;

       use = h.use;

       ++*use;

}

template<class T>

inline JieHandle<T>& JieHandle<T>::operator=(constJieHandle& rhs)

{

       ++*rhs.use;

       RemoveRef();

       use = rhs.use;

       ptr = rhs.ptr;

       return *this;

}

template<class T>

inline T& JieHandle<T>::operator*()

{

       if (ptr)

       {

              return*ptr;

       }

       throwruntime_error("Deference of unboundHandle!");

}

template<class T>

inline constT&JieHandle<T>::operator*()const

{

       if (ptr)

       {

              return*ptr;

       }

       throwruntime_error("Access through unboundHandle!");

}

template<class T>

inline T* JieHandle<T>::operator->()

{

       if (ptr)

       {

              returnptr;

       }

       throw;

}

template<class T>

inline const T*JieHandle<T>::operator->()const

{

       if (ptr)

       {

              returnptr;

       }

       throw;

}

 

template<class T>

inline voidJieHandle<T>::RemoveRef()

{

 

       if(--*use == 0)

       {

              deleteptr;

              ptr = NULL;

              deleteuse;

              use = NULL;

       }

}

       如果想知道它的其他东西,可以去研究一下c++ primer第四版特别版,我的代码跟它如出一辙,只是改一些变量名而已。这里用到了一个东西是引用计数,就是记录有多少个人使用它的意思,当用它的人销毁了,计数变少1,最后剩下自己,如果自己也销毁了,那么就释放空间,这个句柄类跟智能指针有点像,因为你使用它的时候,只管new分配空间,而不用管delete,它自己会帮你完成这个工作的,所以它帮你做了不少工作。

       下面来看看怎么使用它

       // “text.h”

class BaseHandle

{

public:

       BaseHandle(inti)

       {

              index = i;

       }

       intindex;

};

//mian .cpp

#include”text.h”

class DeriveHanlde

{

private:

       JieHandle<BaseHandle> b;

public:

       DeriveHanlde(constJieHandle<BaseHandle>& baseHandle)

       {

              b = baseHandle;

       }

       voidModifyIndex();

};

void DeriveHanlde::ModifyIndex()

{

       b->index = 100;

}

 

void main()

{

       JieHandle<BaseHandle> base = new BaseHandle(0);

       JieHandle<DeriveHanlde> derive = new DeriveHanlde(b);

       derive->ModifyIndex();

       cout<<base->index;

}

上面的结果会是多少呢?没错,就是100,没有全局变量,没有继承,只是BaseHandle成为了其他类的成员了,值得注意的是DeriveHandle的空间没有增大,因为它做的不是复制,而是将其中的成员b成为基类的引用,所以指向的地址还是同一块东西,还有一个好处,不需要我们自己去deleteJieHandle已经帮我们完成了。

为什么derive修改一下indexbaseindex就改变?

       因为它们两个都是指向同一块地址空间,derive修改了index,自然的,baseidnex就会改变了。

       在这里随便提一下,auto_ptrshare_ptr这两个指针模版可以很好的管理资源分配与释放,跟JieHandle的用法类似。只是auto_ptr不能进行正确赋值,一旦执行赋值,则前一个值变为NULL,而share_ptr不会,它支持赋值,JieHandleshare_ptr有点像。考虑下面的代码:

void main()

{

       JieHandle<BaseHandle> base = new BaseHandle(0);

JieHandle<DeriveHanlde> derive = new DeriveHanlde(b); JieHandle<BaseHandle> base2= new BaseHandle(0);

       derive->ModifyIndex();

       cout<<base->index;

       cout<<base2->index;

}

base2index也是100;将share_ptr替换JieHandle的结果一样。如果是auto_ptr的话,则base的值变为NULL;所以使用这几个智能指针的话要选择正确,如果想了解更多的话,去研究一下Mayers的书。

下面极力推荐关于C++的书,

C++ Primer》传世经典之作,无论是初学的还是提高的,都可以从中获益匪浅,不知道多少位大神都这里开始的。

Mayers的《Effective C++》与《More Effective C++》,里面讲的是编程法则,若你想深入了解C++,提高你的编程质量,这两本书非看不可,不然枉费了作者的一片苦心啊。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值