实现相同接口的对象/类之间的C ++数据共享

时间:2018-05-21 13:28:15

标签: c++ data-sharing

通常需要在不同的对象/类之间共享相同的数据。我知道有几种不同的方法:

  1. 全局变量:受大多数人的憎恨和正当理由。
  2. 单身人士:这对谁能够或不能提供有限的控制 修改数据,至少对于下面讨论的问题。
  3. 依赖注入:与单身人士一样的问题。
  4. 有时,这种数据共享会导致设计对此共享数据的封装较弱。经常出现的两种常见情况如下:

    在状态机中实现状态接口的状态需要访问同一组数据。

    class SharedData
    {
    public:
    double GetVar() const {return var;}
    bool GetFlag() const {return flag;}
    void SetVar(double in_var) {var = in_var;}
    void SetFlag(bool in_flag) {flag = in_flag;}
    
    private:
    double var;
    bool flag;
    };
    
    class StateIface
    {
    public:
    virtual void Run(SharedData* in_shared_data) = 0;
    };
    
    class ConcreteStateA : public StateIface
    {
    virtual void Run(SharedData* in_shared_data) final;
    };
    
    class ConcreteStateB : public StateIface
    {
    virtual void Run(SharedData* in_shared_data) final;
    };
    

    此处,ConcreteStateA等具体实施需要访问SharedData,例如SharedData。获取/设置某些数据,可以使用此信息来决定状态转换等。如上例所示,我们可以将SharedData声明为类并提供访问器/更改器。或者我们可以简单地将SharedData声明为结构。但是,在这两种情况下,具体实现都可以修改ConcreteStateA中的任何参数。例如,假设flagConcreteStateA无关,因此无法改变它。但是,使用给定的接口,我们无法控制该行为。 ConcreteStateBConcreteState都可以访问所有数据,并可以获取/设置任何参数。这个问题有更好的设计/解决方案吗?一个为共享数据提供更多保护的一个。或者,我们是否可以某种方式强制执行约束,即某个SharedData只能修改StateInterface的某些参数,同时仍然可以实现公共class SubroutineInterface { public: virutal void DoSubroutine(SharedData* in_shared_data) = 0; } class ConcreteSubroutine : public SubroutineInterface { public: virutal void DoSubroutine(SharedData* in_shared_data) final; };

    实现子例程接口的巨型算法的子例程需要访问同一组数据。

    SQL> SELECT to_date('2018m3', 'YYYY"m"MM') FROM dual
      2  /
    

    与状态机示例相同的问题......

2 个答案:

答案 0 :(得分:2)

您可以通过SharedData 不透明类型

来实现额外保护

library.h

class SharedData;

void foo(SharedData*);

class bar {
public:
  void method(SharedData*);
};

library_private.h

class SharedData {
public:
  int x;
};

library.cpp

#include "library.h"
#include "library_private.h"

void foo(SharedData* d) {
  d->x = 0;
}

void bar::method(SharedData* d) {
  d->x = 1;
}

这样,只有包含library_private.h的cpp文件才能访问SharedData的接口,但SharedData个实例仍然可以在项目的其余部分传递。

唯一棘手的部分是管理SharedData的生命周期,因为大多数时候你必须在堆上分配SharedData,智能指针必须附加自定义删除器。因此,opaque类型通常包含在某种包装器类型中以管理RAII。

这样的事情:

标题中的

class SharedDataImpl;
class SharedData {
public:
  SharedData();
  ~SharedData();

  SharedDataImpl* get() {
    return impl_.get();
  }
private:
  std::unique_ptr<SharedDataImpl> impl_;
};

in .cpp:

SharedData() 
  : impl_(std::make_unique<SharedDataImpl>()) {}

~SharedData() {}

答案 1 :(得分:2)

您可以使用PassKey习语,例如:

class SharedData
{
public:
    class FlagKey
    {
        friend class ConcreteStateA;
        // List here classes which can modify Flag
    private:
        FlagKey() {}
        FlagKey(const FlagKey&) = delete;
    };

    class VarKey
    {
        friend class ConcreteStateB;
        // List here classes which can modify Var
    private:
        VarKey() {}
        VarKey(const FlagKey&) = delete;
    };

public:
    double GetVar() const {return var;}
    bool GetFlag() const {return flag;}
    void SetVar(VarKey, double in_var) {var = in_var;}
    void SetFlag(FlagKey, bool in_flag) {flag = in_flag;}
private:
    double var = 0;
    bool flag = false;
};

然后:

class ConcreteStateA : public StateIface
{
public:
    virtual void Run(SharedData& data) final {
        // data.SetVar({}, 0); // error: calling a private constructor of class 'VarKey'
        data.SetFlag({}, false);
    }
};