2010-12-14 4 views
0

Я работаю с некоторым кодом, где у меня есть следующая настройка.Использование защищенных внешних ресурсов

struct data 
{ 
     void change_safe_member(){} 
     void read_data(){} 
     void change_unsafe_member(){} 
}; 

struct data_processor 
{ 
    std::shared_ptr<data> get_data(){} 
    void return_data(std::shared_ptr<data> my_data) 
    { 
      my_data->change_unsafe_member(); // ONLY data_processor should call this function. 
    } 
}; 

struct client 
{ 
    void foo(std::shared_ptr<data_processor>& my_processor) 
    { 
      auto my_data = my_processor->get_data(); 
      my_data->change_safe_member(); 
      //my_data->change_unsafe_member(); SHOULD NOT BE POSSIBLE TO CALL 
      my_processor->return_data(my_data); 
    } 
}; 

change_unsafe_member следует использовать только внутри процессор, так что я хотел бы, чтобы скрыть его или отключить его для клиента. Но я не знаю ни хороших способов сделать это, не прибегая к уродливым слепков ...

struct internal_data 
{ 
     void change_unsafe_member(){} 
}; 

struct data : public internal_data 
{ 
     void change_safe_member(){} 
     void read_data(){} 
}; 

struct data_processor 
{ 
    std::shared_ptr<data> get_data(){} 
    void return_data(std::shared_ptr<data> my_data) 
    { 
      auto internal_data = std::static_pointer_cast<internal_data>(my_data); 
      internal_data->change_unsafe_member(); 
    } 
}; 

Любой знает хороший шаблон для использования в подобных ситуациях? Может быть, шаблон посетителя или что-то подобное?

EDIT:

Как было отмечено в комментариях один мог объявить другу классов, есть, однако, одна проблема ... следующий не будет работать.

struct data 
{ 
     void change_safe_member(){} 
     void read_data(){} 
private: 
     friend class data_processor; 
     virtual void change_unsafe_member(){} 
}; 

struct data_decorator : public data 
{ 
     data_decorator(const std::shared_ptr<data>& decoratee) : decoratee_(decoratee){} 
     void change_safe_member(){decoratee_->change_safe_member();} 
     void read_data(){decoratee_->read_data();} 
private: 
     virtual void change_unsafe_member() 
     { 
      std::cout << "Hello!"; // Add functionality 
      decoratee_->change_unsafe_member(); // Won't work... compiler error 
     } 
     std::shared_ptr<data> decoratee_; 
}; 

// Another example 
struct data_group_decorator : public data 
{ 
     data_group_decorator (const std::vector<std::shared_ptr<data>>& decoratees) : decoratees_(decoratees){} 
     void change_safe_member(){decoratee_->change_safe_member();} 
     void read_data(){decoratee_->read_data();} 
private: 
     virtual void change_unsafe_member() 
     { 
      for(size_t n = 0; n < decoratees_.size(); ++n) 
        decoratees_[n]->change_unsafe_member(); // Won't work... compiler error 
     } 
     std::vector<std::shared_ptr<data>> decoratees_;; 
}; 
+1

сделать его приватным и объявить 'data_processor' другу по электронной почте класс? –

+0

Это действительно работает в этом упрощенном случае, я обновляю свой вопрос с помощью более сложного примера. – ronag

+1

Вы также можете указать 'friend void data_processor :: return_data (.....)', чтобы ограничить «дружественность» определенному члену 'data_processor', только если все охватывающие любовь слишком много. –

ответ

1

Вы можете сделать это с наследованием.

struct Y; 
struct X { 
    friend struct Y; 
private: 
    change_unsafe_member() {} 
}; 
struct Y { 
protected: 
    change_unsafe_member(X& x) { x.change_unsafe_member(); } 
}; 
struct some_other : Y { 
    X x; 
    change_safe_member() { change_unsafe_member(x); } 
}; 

Любой класс, который наследует от Y может получить дружбу на Х для любых функций, Y определяет, как эффективно передает из X.

1

Ваш последний пример выглядит так, как будто вы действительно просите унаследованную дружбу; т. е. вы хотите иметь иерархию decorator - производные классы, которым разрешено вызывать функцию-член private в data. Вот ответил (с «вообще нет») в другом месте:

Why does C++ not allow inherited friendship?

полиморфизм может обеспечить некоторое облегчение в вашем конкретном случае, сделать class data_decorator «почти чистый» базовый класс виртуального, с единственным невиртуальным членом будучи protected change_unsafe_member(), и сделать это, в свою очередь, friend от class data. Все декораторы наследуют от data_decorator и вызывают его защищенный невиртуальный член.

Смежные вопросы