【问题标题】:Differing access on a member of a class according to the context根据上下文对类成员的不同访问
【发布时间】:2011-11-30 18:03:10
【问题描述】:

假设我有一个 MainApp 类,它通过接口 FrontEnd 使用动态库的方法

FrontEnd 使用 Data 类的内部实例(包含在 BackEnd 类中)

该类Data只包含一个成员及其访问器,没有公共方法来操作该成员

好的,现在 MainApp 不知道 Data 并且无法访问它,但它需要间接地操作它

我的目标是创建某种引用来保持指向具有 2 种行为的 Data 的指针

  1. 在 MainApp 中禁止访问数据
  2. 在前端允许访问数据

我列出了一些解决方案,例如 PIMPL idiom、Bridge 或 Adapter 模式,但问题是我不想将 Reference 用作接口,而是将其用作支架

我该如何处理?

这里有一些代码来说明:

数据.hpp

struct Data {
    Data(int i):member(i){}
    int getMember();
private :
    int member;
};

BackEnd.hpp

#include "Data.hpp"

struct BackEnd {
    BackEnd(){}
    Data* createData(int i) {
      Data* d = new Data(i);
      mDatas.push_back(d);
      return d;
    }

    void doSomething(Data* d, int param) {
      int r = param+d->getMember();
      /*do other things with d*/
    }
private:
    vector<Data*> mDatas;
};

参考.hpp

#include //???

struct Reference {
    Reference(Data* d):mData(d){}
private:
    //no access to data->member
    Data* mData;
};

前端.hpp

#include "Data.hpp"
#include "Reference.hpp"
#include "BackEnd.hpp"

struct FrontEnd {
    Reference* createData(int i) {
      Data* d = mBackEnd->createData(i);
      //conversion Data to Reference
      Reference ref = new Reference(d);
      return ref;
    }

    void doSomething(Reference* ref) {
      //In the Front-End, I want an access to Ref->mData
      Data* d = ref->getData();//Allows access to Ref->mData
      int result = mBackEnd->doSomething(d);
    }
private:
    BackEnd* mBackEnd;
};

MainApp.hpp

//I don't want to reference Data.hpp
#include "Reference.hpp"
#include "FrontEnd.hpp"

struct MainApp {
    Reference* createRef(){ mRef = mFrontEnd->createData(8);}
    void doSomething(){ mFrontEnd->doSomething(mRef); }
private:
    FrontEnd* mFrontEnd;
    Reference* mRef;
    //I want to keep a reference to Data without using Data directly
    //Forbids access to mRef->mData
};

【问题讨论】:

  • class Reference 文件需要包含Data.hpp,除非你正在做整个pImpl 的事情。

标签: c++ design-patterns reference friend access-control


【解决方案1】:

考虑使用友谊 - 即使FrontEnd 成为Referencefriend,这样您就可以在Reference 中拥有一个protected 成员,这将允许您获得Data*。在Reference.h 中,包括FrontEnd.h(允许友谊),在FrontEnd.h 中,使用Reference 作为前向声明(即不包括标题)。仅在 FrontEnd 的实现文件中包含标头。您必须将所有定义(在FrontEnd.h 中)也移动到实现文件中。

现在MyApp 可以愉快地持有ReferenceData* 只能由FrontEnd 获得。

【讨论】:

  • 好的,它工作;如果我希望数据被模板化怎么办?是否有任何设计模式可以做到这一点,或者我是否坚持使用关键字“朋友”
  • 在这种情况下您可以使用继承 - 所以将Reference 设为基类,并且您可以拥有一些可以容纳模板化Data 实例的派生实例。在MyApp 中,持有一个指向Reference 的智能指针,然后使用访问者模式通过Reference 做一些事情- 是不是一清二楚? :)
  • @Nim:为什么不简单地将 Reference 类也模板化?
  • @Mooing,然后你引入一个耦合,你必须以某种方式将该类型引入MyApp
【解决方案2】:

如果您想允许外部类访问另一个类的内部,您可以将其设置为friend

struct Foo;

struct Bar {
private:
  friend struct Foo;
  int count;
};

struct Foo {
  void doBarStuff(Bar &bar) {
    bar.count = 2;
  }
};

这显然是一种权衡。可以不同地考虑这两个结构,但是如果它们访问彼此的内部,它们就没有太多的关注点分离。谨慎使用。

当您这样做时,最好通过方法调用访问内部,而不是直接操作它们。看起来您正在增加复杂性,并且在某种程度上是这样。不过,它使您的访问意图变得清晰。

struct Foo;

struct Bar {
private:
  friend struct Foo;
  void setCount(int c) {
    if (count < 0)
      throw std::logic_error("out of range");
    count = c;
  }
  int count;
};

struct Foo {
  void doBarStuff(Bar &bar) {
    bar.setCount(2);
  }
};

例如,您不希望该计数检查在整个 Foo 中乱扔垃圾。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-11
    • 1970-01-01
    • 2018-05-29
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 2015-04-28
    相关资源
    最近更新 更多