Различный доступ к члену класса в зависимости от контекста - PullRequest
0 голосов
/ 04 октября 2011

Допустим, у меня есть класс MainApp, использующий методы динамической библиотеки через интерфейс FrontEnd

FrontEnd внутренне использует экземпляры класса Data (содержатся в классе BackEnd)

Этот класс Dataсодержит только элемент и его метод доступа, нет открытого метода для управления элементом

Хорошо, теперь MainApp не знает данных и не может получить к ним доступ, но ему необходимо косвенно манипулировать им

Моя цельдолжен создать какую-то ссылку, сохраняющую указатель на данные с двумя поведениями

  1. , запрещающий доступ к данным в MainApp
  2. разрешение доступа к данным в FrontEnd

Я перечислил некоторые решения, такие как PIMPL idiom, Bridge или Pattern Adapter, но проблема в том, что я не хочу использовать Reference как интерфейс, а просто как держатель

Как я могу справиться с этим?

Вот пример кода для иллюстрации:

Data.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;
};

Reference.hpp

#include //???

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

переднийEnd.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
};

Ответы [ 2 ]

2 голосов
/ 04 октября 2011

Подумайте об использовании дружбы - то есть сделайте FrontEnd a friend из Reference, таким образом, вы можете иметь protected члена в Reference, который позволит вам получить Data*. В Reference.h включите FrontEnd.h (чтобы разрешить дружбу), в FrontEnd.h используйте Reference в качестве предварительной декларации (т.е. не включайте заголовок). Включите только заголовок в файл реализации для FrontEnd. Вам придется переместить все определения (в FrontEnd.h также в файл реализации.

Теперь MyApp может счастливо держать Reference, но Data* может быть получен только FrontEnd.

2 голосов
/ 04 октября 2011

Если вы хотите разрешить внешним классам доступ к внутренним объектам другого, вы можете установить его как 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.

...