2017-07-03 2 views
0

Comment puis-je appeler dinamiquement fonction de la forme: childA.function(childB) alors que leurs types statiques sont les deux parents?Comment appeler fonction dynamiquement avec l'argument de polymorphisme

et avec plus de détails:

J'ai un projet physique où je dois calculer le potentiel de 2 molécules. Mais j'ai 2 types de molécules, LC et Col, et chaque type a ses propres paramètres et d'autres choses, mais je veux être capable d'appeler dynamiquement le potentiel de chaque molécule.

donc j'ai essayé ceci:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    virtual double potential(const Molecule * mol){} 
    virtual double potential(const Col * mol){} 
    virtual double potential(const LC * mol){} 
}; 

class LC : public Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const Molecule * mol) {return 1;} 
    virtual double potential(const LC * mol) {return 2;} 
    virtual double potential(const Col * mol) {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const Molecule * mol) {return 4;} 
    virtual double potential(const LC * mol) {return 5;} 
    virtual double potential(const Col * mol) {return 6;} 
}; 

int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

Mais j'obtenir le résultat de 4, il se trouve que la fonction est appelée de façon statique, ce qui signifie que, puisque le type statique de mol1 est Molecule la fonction appelée est:

virtual double potential(const Molecule * mol) {return 4;} 

et non

virtual double potential(const LC * mol) {return 5;} 

est-il de toute façon d'appeler la fonction Dyna mically (dans la conception OOP) sans l'utilisation de typeid en elle?

réponse complète:

Après enquête avec Peter conseils ce se révéler être un problème à double expédition classique, la solution complète est juste d'appeler dans un autre virtuel similaire virtuel ceci:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 


using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    virtual double potential(const Molecule * mol) const = 0; 
    virtual double potential(const Col * mol) const = 0; 
    virtual double potential(const LC * mol) const = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const Molecule * mol) const {return mol->potential(this);} 
    virtual double potential(const LC * mol) const {return 2;} 
    virtual double potential(const Col * mol) const {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const Molecule * mol) const {return mol->potential(this);} 
    virtual double potential(const LC * mol) const {return 5;} 
    virtual double potential(const Col * mol) const {return 6;} 
}; 

int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

et cela renvoie effectivement 3 comme souhaité.

+0

Votre code source ne compile pas. Les coupables sont les fonctions membres de Molecule. Vous pouvez également renommer le membre de données "Molecule". Peut-être avez-vous oublié de faire ces choses virtuelles? Les fonctions ne sont pas appelées statiquement. Veuillez fournir un [MCVE] (https://stackoverflow.com/help/mcve). – Ron

+1

Recherchez le modèle de visiteur. – Peter

Répondre

1

Vous appelez toujours le potentiel (Molecule *), puisqu'il s'agit du type d'argument que vous transmettez. Si vous voulez le faire dynamiquement (c'est-à-dire prendre une décision d'exécution), vous devrez effectuer une conversion dynamique pour décider du type actif et appeler la bonne fonction. Vous pourriez, par exemple, implémentez la fonction avec l'argument de type base uniquement dans la classe de base, vérifiez le type réel, puis appelez la fonction surchargée avec le bon type. Le code pourrait alors ressembler à ceci:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    virtual ~Molecule() {} 
    /// more data and functions should be here regarding the molecule 
    double someBulshit; 
    double potential(const Molecule * mol); 
    virtual double potential(const Col * mol) = 0; 
    virtual double potential(const LC * mol) = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    virtual ~LC() {} 
    /// more data and functions should be here regarding the LC molecule 
    virtual double potential(const LC * mol) {return 2;} 
    virtual double potential(const Col * mol) {return 3;} 
}; 
class Col : public Molecule 
{ 
    public: 
    virtual ~Col() {} 
    /// more data and function should be here regarding the Col molecule 
    virtual double potential(const LC * mol) {return 5;} 
    virtual double potential(const Col * mol) {return 6;} 
}; 

double Molecule::potential(const Molecule * mol) { 
    const Col *mol_as_Col = dynamic_cast<const Col*>(mol); 
    const LC *mol_as_LC = dynamic_cast<const LC*>(mol); 
    if(mol_as_Col) { 
    return potential(mol_as_Col); 
    } 
    else if(mol_as_LC) { 
    return potential(mol_as_LC); 
    } 
    else { 
    throw; 
    } 
} 


int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 

Le résultat sera 5 et non 6 comme vous avez écrit dans votre question, puisque vous mettez dans un type LC et faire l'appel sur le colonel I ont également ajouté les disparus destructeurs virtuels, puisque les classes polymorphes devraient toujours l'avoir. Vous pouvez également essayer de l'implémenter avec du code de modèle et éviter d'utiliser le polymorphisme d'exécution en premier lieu (c'est-à-dire ne jamais contenir de pointeurs de type Molecule *). Si vous êtes intéressé, je peux trouver un exemple, mais puisque vous demandez spécifiquement une solution dynamique, cela ne semble pas être la réponse à cette question.

EDIT: Suit une démonstration de modèle. Cela n'a pas vraiment de sens sans le contexte.J'ai ajouté une fonction printPotential() qui montre comment vous pouvez écrire le reste du code:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 

template<typename MOLECULE1, typename MOLECULE2> 
void printPotential(MOLECULE1 *mol1, MOLECULE2 *mol2) { 
    double my_potential = mol1->potential(mol2); 
    printf("%f",my_potential); 
} 

class Col; 

class LC 
{ 
    public: 
    /// more data and functions should be here regarding the LC molecule 
    double potential(const LC * mol) {return 2;} 
    double potential(const Col * mol) {return 3;} 
}; 
class Col 
{ 
    public: 
    /// more data and function should be here regarding the Col molecule 
    double potential(const LC * mol) {return 5;} 
    double potential(const Col * mol) {return 6;} 
}; 


int main(int argc, char* argv[]) 
{ 
    Col *mol1 = new Col(); 
    LC *mol2 = new LC(); 

    printPotential(mol1, mol2); 
} 

En fait, en écrivant cela, je pense qu'il pourrait y avoir une troisième méthode (et en fait préféré): Vous devez trouver un algorithme abstrait comment calculer le potentiel entre deux molécules en utilisant seulement des informations communes qui peuvent faire partie de la classe de base (ou obtenues par des appels de fonctions virtuelles de la classe de base). Dans ce cas, vous pouvez avoir une seule implémentation de potential() (soit en tant que fonction membre de la classe de base avec un seul argument de type Molecule *, soit en tant que fonction non membre avec deux arguments de type Molecule *). Si je suppose que le potentiel entre les deux molécules est la différence de deux potentiels « absolues » (comme un exemple stupide), il pourrait ressembler à ceci:

#include <iostream> 
#include <typeinfo> 
#include <stdio.h> 

using namespace std; 
class Col; 
class LC; 

class Molecule 
{ 
    public: 
    virtual ~Molecule() {} 
    /// more data and functions should be here regarding the molecule 
    double potential(const Molecule * mol) { 
    return mol->getAbsolutePotential() - getAbsolutePotential(); 
    } 
    virtual double getAbsolutePotential() const = 0; 
}; 

class LC : public Molecule 
{ 
    public: 
    virtual ~LC() {} 
    /// more data and functions should be here regarding the LC molecule 
    double getAbsolutePotential() const {return 42.0;} 
}; 
class Col : public Molecule 
{ 
    public: 
    virtual ~Col() {} 
    /// more data and function should be here regarding the Col molecule 
    double getAbsolutePotential() const {return 120.0;} 
}; 


int main(int argc, char* argv[]) 
{ 
    Molecule * mol1 = new Col(); 
    Molecule * mol2 = new LC(); 

    double my_potential = mol1->potential(mol2); 
    printf ("%f",my_potential); 
} 
+0

Je pensais que la solution dynamique est plus la conception comme OOP. Si vous pensez que les modèles conviennent mieux ici, je serai heureux de voir ce genre de solution. J'ai aussi corrigé l'erreur de retour 6, merci! – pio

+1

Voir les modifications de ma réponse :-) –