2010-12-14 3 views
0

Je travaille avec du code où j'ai la configuration suivante.Utilisation de ressources externes protégées

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); 
    } 
}; 

Le change_unsafe_member ne doit être utilisé en interne par le processeur, donc je voudrais le cacher ou le désactiver pour le client. Mais je ne connais pas de belles façons de le faire sans avoir recours à des moulages laides ...

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(); 
    } 
}; 

Quelqu'un sait d'un bon modèle à utiliser dans des situations comme celle-ci? Peut-être un modèle de visiteur ou quelque chose de similaire?

EDIT:

Comme indiqué dans les commentaires on pourrait déclarer les classes d'ami, il y a cependant un problème ... ce qui suit ne marchera pas.

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

le rendre privé et de déclarer 'data_processor' une classe ami? –

+0

Cela fonctionnerait en effet dans ce cas simplifié, je vais mettre à jour ma question avec un exemple plus compliqué dans un instant. – ronag

+1

Vous pouvez également spécifier 'friend void data_processor :: return_data (.....)' pour restreindre "convivialité" à un membre particulier de 'data_processor' que si tout l'amour englobant est trop. –

Répondre

1

Vous pouvez rendre cela possible avec l'héritage.

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); } 
}; 

Toute classe qui hérite de Y peut gagner l'amitié de X pour toutes les fonctions Y définit aussi efficacement avant de X.

1

Votre dernier exemple ressemble à ce que vous demandez vraiment est l'amitié héritée; c'est-à-dire que vous voulez avoir une hiérarchie de decorator - classes dérivées qui sont toutes autorisées à appeler la fonction membre private dans data. Cela a répondu (avec « généralement pas ») ailleurs:

Why does C++ not allow inherited friendship?

Polymorphisme pourrait apporter un certain soulagement dans votre scénario spécifique, faire class data_decorator un « presque pur » classe de base virtuelle, avec le seul membre nonvirtual étant un protected change_unsafe_member(), et faire cela à son tour un friend de class data. Tous les décorateurs hériteraient de data_decorator et appeleraient leur membre non virtuel protégé.

Questions connexes