软件开发随笔:用C++实现上下层级的类的数据共享

一般在工程的实现中,我都喜欢把oop发挥到极致,也就是把一切都封装成类,并且用指针实现类之间的层级调用,那么在面临类之间的数据流通与共享时,存在一个原则,称作接口与实现分离,下层的类提供接口,上层通过接口获取下层的数据,或者向下层写数据。那么,如果上下级需要数据流通,频繁调用双方接口不仅繁琐也容易出错。

有的同学,包括我原来,喜欢将不同的层级写在不同进程,同时用ros等进程间通信方式传递数据,这样很方便但是也有风险,同时多个进程也增大了开销。近年来养成的一个好习惯就是使用共享指针来分享数据,父类将需要共享的数据制作成共享指针的形式,然后共享给子类,每个类中持有一个,而每个指针都指向的同一个对象,只需在任意地方修改对象,其他类也会立即响应。

如下的程序所示,vector<int>是父亲所持有的数据,此时它将数据制作为共享指针,同时在儿子的构造时传递之,这样两个类就能“心有灵犀”般地进行数据流通。

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

namespace test
{
class Child
{
public:
  Child(std::shared_ptr<std::vector<int> >& info)
  {
    important_inform_ = info;
  }
private:
  std::shared_ptr<std::vector<int> > important_inform_;

};

class Father
{
public:
  Father()
  {
    important_inform_.reset(new std::vector<int>);
    child_.reset(new Child(important_inform_));
  }
private:
  std::shared_ptr<Child> child_;

  //std::vector<int> important_inform_;
  std::shared_ptr<std::vector<int> > important_inform_;
};


}/* end of namespace */

int main(int argc, char** argv)
{
  test::Father father;
  return 0;
}

不过,事情不会总是称心如意,假设现在存在“积重难返”的局面,之前由于太菜,或者考虑不周到,或者万恶的产品经理又新增了一些需求,原来设定的数据(vector<int>)已经写的到处都是了,将它改成共享指针要进行大量工作,现在儿子突然需要使用或修改父亲的该数据,用一般的方法恐怕就难以奏效了。

这里提供了一种“亡羊补牢”的方法,将父亲的函数或方法用函数指针的形式传递给儿子,儿子手中持有父亲的一个回调函数,这样儿子便可以调用该函数指针,来使用父亲的函数。为了保险起见,建议大家用std::function来进行封装。

#include <iostream>
#include <vector>
#include <memory>
#include <functional>

using namespace std;

namespace test
{
class Child
{
public:
  Child()
  {}

  void registerFatherCallback(std::function<void(int)>& f)
  {
    father_func_ = f;
  }

  void changeFatherData(int item)
  {
    father_func_(item);
  }
private:
  //std::shared_ptr<std::vector<int> > important_inform_;
  std::function<void(int)> father_func_;
};

class Father
{
public:
  Father()
  {
    child_.reset(new Child());

    auto changeData = [&](int item)
    {
      important_inform_.push_back(item);
      cout<<"important_inform_.size():"<<important_inform_.size()<<endl;
    };

    std::function<void(int)> f = changeData;
    child_->registerFatherCallback(f);
  }

  std::shared_ptr<Child> child_;

private:

  std::vector<int> important_inform_;
  //std::shared_ptr<std::vector<int> > important_inform_;
};


}/* end of namespace */

int main(int argc, char** argv)
{
  test::Father father;
  father.child_->changeFatherData(0);
  father.child_->changeFatherData(1);

  return 0;
}

在工程开发的过程中,总是有迷的事情出现,无论是自己原来脑残,还是产品经理蜜汁需求,都是正常的沟通成本,尤其是多人合作开发时要大量修改格式更可能造成难以预估的奇怪bug浪费大量时间,因此掌握一些“亡羊补牢”的方法也是很有必要的,但是,并不代表我们在初始构思的时候就囫囵吞枣不假思索,软件开发就像是绘画或者围棋,在动手之前不大致思考好框架,成果将会凌乱不堪,反过来套牢了自己。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值