2009-02-27 7 views
0

ignorer cela, j'ai pensé à une solution de contournement impliquant la génération d'en-tête. Ce n'est pas la meilleure solution, mais cela fonctionne. Cette question est étrange à comprendre. Fondamentalement, je veux appeler une fonction virtuelle qui n'a pas été déclarée dans la lib ou dll et l'utiliser comme normal (mais ne l'a pas mis en œuvre/vide func).étendre une classe de base abstraite sans recompilation de source?

J'ai une classe de base abstraite dans ma bibliothèque. Tous mes plugins en héritent, le plugin utilisateur hérite de cette classe et son application utilise cette classe comme un pointeur de plugin. Je veux que cet utilisateur puisse étendre la classe et ajouter ses fonctions. Le problème est, je suis sûr que s'il ajoute une fonction virtuelle et essaie de l'appeler, le code va planter en raison de mes objets n'ayant pas les données supplémentaires dans son vtable. Comment puis-je contourner cela? J'ai pensé en hériter, mais cela entraînerait de vilains problèmes lorsqu'un troisième utilisateur vient jouer. Je ne veux pas qu'il soit catalogué pour envoyer les fonctions étendues.

Je pensais à une fonction msg comme intptr_t sendMsg (enum msgName, void * argv); Mais cela supprime le safty et je devrais tout typer. Quelle est la meilleure solution pour cela? Je préfère utiliser vtables, puis utiliser une fonction sendMsg. Comment puis-je contourner cela?

+0

pouvez-vous poster du code? – cbrulak

+0

Peut-être ai-je mal compris la question, mais je penserais que tant que la classe dérivée est correctement instanciée, elle ne tomberait pas en panne. Pourriez-vous élaborer? – codelogic

+0

Si son code est celui à "nouveau" de sa classe, cela fonctionnera bien. (Bien que, comme codelogic, peut-être que je ne "reçois" pas la question.) –

Répondre

1

Demandez-vous si vous pouvez ajouter des fonctions virtuelles à la classe de base sans recompiler? La réponse courte à cela est "non". La réponse longue est dans votre question, vous devrez fournir une sorte d'interface générique "call_func" qui vous permettrait d'appeler des fonctions "dynamiquement".

1

Je pense que vous pouvez utiliser le registre et le mécanisme de rappel

Votre plugin peut fournir Classe abstraite de base "de base" et la fonction

Register(Base *); 

maintenant client peut se interfacer appeler Registre Fonction

Register(b); 

où b est défini comme

Base *b = new Derived; 

où DERIVE nouvelle classe dérivée de la base

1

Je ne suis pas sûr à 100% que je vois le problème.
Si le type dérivé user1 étend votre classe de base (avec des méthodes plus virtuelles), alors cela devrait être bien (bien sûr votre code ne saura jamais ou comprendre ces nouvelles méthodes, mais probablement vous ne seriez pas les appeler:

class B 
{ 
    virtual void doStuff() { /* Nothing */} 
}; 

// User 1 version: 
class U1: public B 
{ 
    virtual void doStuff() 
    { 
     this->doA(); 
     this->doB(); 
    } 
    virtual void doA() {} 
    virtual void doB() {} 
}; 

// User 2 version can extend it differently. 

note:
Si vous êtes inquiet par tranchage parce que vous stockez des objets dans un vecteur qui est un problème légèrement différent

std::vector<B> objs; 
objs.push_back(U1()); 

std::for_each(objs.begin(),objs.end(),std::mem_fun_ref(&B::doStuff)); 

ici, le problème est qu'un type défini par l'utilisateur U1 ne peut pas être copié dans le vecteur. parce que le vecteur ne contient que B objets. Cela coupe les données supplémentaires contenues dans U1.

La solution à ce problème est que vous devez maintenir des pointeurs dans le vecteur. Cela conduit bien sûr à d'autres problèmes avec une sécurité exceptionnelle. Donc boost a le conteneur ptr_vector <> pour contenir les objets correctement tout en les laissant utilisés comme des objets.

#include <boost/ptr_container/ptr_vector.hpp> 

...... 

boost::ptr_vector<B> objs; 
objs.push_back(new U1()); 

std::for_each(objs.begin(),objs.end(),std::mem_fun_ref(&B::doStuff)); 
Questions connexes