2010-11-03 7 views
3

J'ai une classe - PluginLoader qui traite avec une autre classe Plugin pour mener à bien ses fonctions. La classe Plugin utilise certaines fonctions dans PluginLoader. Ces deux classes sont des classes de base abstraites donc je ne peux pas déclarer Plugin comme ami de PluginLoader. Et je ne veux pas que les fonctions Plugin soient disponibles dans l'interface publique de PluginLoader car elles n'ont aucune pertinence pour l'utilisateur de PluginLoader. Est-ce un problème courant? Comment le résoudre?Comment exposer un sous-ensemble de l'interface publique à une classe

EDIT: Exemple de code

class PluginLoader 
{ 
    public: 
     virtual void RegisterPlugin(Plugin*) = 0; 
     virtual void RegisterFunction(int, Plugin*) = 0; 
}; 

class Plugin 
{ 
    public: 
     virtual void Load(PluginLoader&) = 0; 
} 

class PlugImp : public Plugin 
{ 
    public: 
     virtual void Load(PluginLoader& oPLoader) 
     { 
     //Do stuff 
     oPLoader.RegisterPlugin(this); 
     } 
} 

Bien que je veux RegisterPlugin soit disponible pour la classe Plugin, il n'y a pas de point laisser visible aux autres utilisateurs de PluginLoader classe.

EDIT2: @chubsdad

#include <iostream> 

using namespace std; 

class PluginLoader; 
class Plugin 
{ 
    public: 
     virtual void Register(PluginLoader&) = 0; 
     virtual ~Plugin() = 0; 
}; 

class PluginLoader 
{ 
    public: 
     virtual void Load() = 0; 

     virtual ~PluginLoader() = 0; 

    private: 
     friend class Plugin; 
     virtual void RegisterPlugin(Plugin&) = 0; 
}; 

class PluginImp : public Plugin 
{ 
    public: 
     void Register(PluginLoader& oPLoader) 
     { 
      oPLoader.RegisterPlugin(*this); 
     } 
}; 

class PluginLoaderImp : public PluginLoader 
{ 
    public: 
     void Load() 
     { 
      Plugin* pP = new PluginImp(); 
      pP->Register(*this); 
     } 

    private: 
     void RegisterPlugin(Plugin& oP) 
     { 
      cout << "PluginLoaderImp::RegisterPlugin" << endl; 
     } 
}; 

int main() 
{ 
    PluginLoader* pPLoader = new PluginLoaderImp(); 
    pPLoader->Load(); 
} 

Cela jette l'erreur du compilateur:

main.cpp: In member function ‘virtual void PluginImp::Register(PluginLoader&)’: 
main.cpp:22: error: ‘virtual void PluginLoader::RegisterPlugin(Plugin&)’ is private 
main.cpp:30: error: within this context 

Ce qui nous amène plein cercle. Ou y a-t-il quelque chose qui me manque?

Répondre

1

En supposant que votre interface PluginLoader contient plus que les méthodes Register... et que vous souhaitez manipuler des chargeurs via cette interface mais fournissez un canal de communication séparé entre le plugin et le chargeur vous pouvez simplement créer une autre interface, PluginRegistra, peut-être, qui aurait les méthodes publiques Register... dessus.

Héritez-en en privé dans votre chargeur de plug-in et implémentez les méthodes Register... en tant que fonctions privées dans le chargeur. Personne ne peut accéder aux méthodes Register... via la classe plugin, ils doivent y accéder via l'interface PluginRegistra et seul le chargeur peut se convertir à ce type car l'héritage est privé.

Maintenant, passez simplement le chargeur au plugin exactement comme vous le faites maintenant; La méthode Load() du plug-in prend maintenant une interface PluginRegistra. Aucune amitié nécessaire. Seul le plugin loader peut se présenter comme une instance de PluginRegistra en raison de l'héritage privé.

Un exemple, comme demandé, notez qu'il n'a pas vu un compilateur.

class PluginLoader 
{ 
    public: 
     virtual void LoadPlugin(Plugin*) = 0; 
}; 

class PluginRegistra 
{ 
    public: 
     virtual void RegisterPlugin(Plugin*) = 0; 
     virtual void RegisterFunction(int, Plugin*) = 0; 
}; 

class Plugin 
{ 
    public: 
     virtual void Load(PluginRegistra&) = 0; 
} 

class PlugImp : public Plugin 
{ 
    public: 
     virtual void Load(PluginRegistra& oPLoader) 
     { 
     //Do stuff 
     oPLoader.RegisterPlugin(this); 
     } 
} 

class LoaderImp : public PluginLoader : private PluginRegistra 
{ 
    public : 
     virtual void LoadPlugin(Plugin* plugin) 
     { 
     plugin.Load(this); 
     } 

    private : 

     virtual void RegisterPlugin(Plugin*) 
     { 
     } 

     virtual void RegisterFunction(int, Plugin*) 
     { 
     } 
} 
+0

Pretty artificiel :). Pouvez-vous s'il vous plaît fournir un exemple de code? – nakiya

+0

Quelqu'un peut-il m'expliquer cela en détail? :(J'ai essayé de faire ce à quoi il ressemble, il me demande de faire sans résultat – nakiya

+0

Ce n'est pas du tout artificiel Logiquement, vous avez deux interfaces séparées à votre plugin loader, l'interface qu'il expose aux plugins pour se permettre pour l'enregistrer et l'interface qu'il expose au monde, alors implémentez-le en tant que tel –

1

Déplacez les fonctions sur PluginLoader. Étant donné le caractère vague de la question, je devrais peut-être mentionner que vous pouvez passer un tas de fonctions connexes comme argument en passant un objet qui fournit les fonctions. Et vous pouvez hériter d'une classe qui fournit les fonctions. Etc.

Vive & HTH.,

2

réponse avant l'OP avaient extrait de code

Je ne vois pas le problème avec des amis que vous soulignez. Deux classes abstraites peuvent être des amis l'un de l'autre. Il n'y a absolument aucun problème.

Voici ce que je suppose que vous indiquez ... (juste un exemple de code illustratif)

struct pluginloader; 

struct plugin{ 
public: 
    void publicm(pluginloader &r); 
    virtual ~plugin() = 0;    // abstract 
private: 
    void privatem(pluginloader &r); // may be virtual in real code 
}; 

struct pluginloader{ 
public: 
    void publicm(){}; 
    virtual ~pluginloader() = 0;  // abstract 
private: 
    void privatem(){}     // may be virtual in real code 
    friend struct plugin;    // friend declaration 
}; 

void plugin::publicm(pluginloader &r){ 
    r.privatem();      // use private methods of pluginloader 
} 

void plugin::privatem(pluginloader &r){ 
    r.privatem();      // use private methods of pluginloader 
} 

plugin::~plugin(){} 
pluginloader::~pluginloader(){} 

struct APlugin : plugin{ 
    ~APlugin(){} 
}; 

struct ALoader : pluginloader{ 
    ~ALoader(){} 
}; 

int main(){ 
    APlugin apl; 
    ALoader ald; 

    apl.publicm(ald); 
} 
+0

Votre exemple fonctionne pour le moment. Mais que se passe-t-il quand vous dérivez de 'Plugin' et' PluginInfo'? – nakiya

+0

@nakiya: ce n'est pas un problème. Voir le code mis à jour – Chubsdad

+0

BTW, je pense que vous voulez dire PluginLoader et non PluginINfo? – Chubsdad

Questions connexes