Instantiation de telle ou telle classe en fonction d'un choix de l'utilisateur [Résolu]

Signaler
Messages postés
4
Date d'inscription
dimanche 12 juillet 2009
Statut
Membre
Dernière intervention
13 juillet 2009
-
Messages postés
4
Date d'inscription
dimanche 12 juillet 2009
Statut
Membre
Dernière intervention
13 juillet 2009
-
Bonjour,
j'aurais besoin d'aide ou de conseils. Voici ma question:

Mon programme doit former quelque chose de façon modulaire, composé de 6 blocs. Pour chacun des blocs, il y a plusieurs possibilités (plusieurs classes héritées).

class Prog {
public:
A *a;
B *b;
C *c;
D *d;
E *e;
F *f;
};

Je voudrais que les classes soient instantiées en fonction du choix de l'utilisateur.
Par exemple, l'utilisateur me donne en entrée {4,2,1,8,3,5}. Donc:

Prog.A = new A4;
Prog.B = new B2;
Prog.C = new C1;
Prog.D = new D8;
Prog.E = new E3;
Prog.F = new F5;

Je ne peux pas faire de switch du style:

Switch(input)
case 1: Prog.A = new A1;
case 2: Prog.A = new A2;

Je peux avoir des centaines de possibilités, c'est donc inenvisageable.

Je veux avoir une sorte de table de correspondance mais je ne sais pas comment l'implémenter.

J'espère être clair, je tenterais de préciser si ce n'est pas le cas.

Quelqu'un aurait-il une piste ou une solution à mon problème ?

Merci.

7 réponses

Messages postés
3829
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
8 janvier 2021
114
Je peux te proposer une solution, pour émuler cela. Vu qu'en C++, on peut pas mettre un type (en Java c'est une classe qui s'appelle Class<?>), on va émuler cela avec des méthodes statiques.

Pour obliger l'utilisateur à créer des classes qui contiennent une méthode statique "instance()", on va créer une classe templaté qui va s'en assurer (et au passage permettre d'émuler un héritage de méthode statiques, cf curiously recurring template pattern).

#include
#include <map>

class Security
{
public:
  virtual void hello() const
  {
    std::cout << "Security" << std::endl;
  }
};

template <class Derived>
struct SecurityType
{
  static Security* instanciate()
  {
    return Derived::instanciate();
  }
};

class Encryption : public Security, public SecurityType<Encryption>
{
public:
  virtual void hello() const
  {
    std::cout << "Encryption" << std::endl;
  }

  static Security* instanciate()
  {
    return new Encryption;
  }

};

class Authentication: public Security, public SecurityType
{
public:
  virtual void hello() const
  {
    std::cout << "Authentication" << std::endl;
  }

  static Security* instanciate()
  {
    return new Authentication;
  }
};

typedef Security* (*pFuncInstanciate) ();

int main()
{
  std::map table;
  table[4] = Encryption::instanciate;
  table[1] = Authentication::instanciate;

  int choice = 0;
  std::cin >> choice;
  Security* sec = table[choice]();

  sec->hello();

  delete sec;
  return 0;
}

NB: Si on choisit un nombre différent de 1 ou 4, l'appli plante. Je ne gère pas les erreurs, c'est juste un exemple.
Messages postés
3829
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
8 janvier 2021
114
J'ai du mal à saisir la finalité de la chose, mais cela ressemble à des classes identiques dont l'un des attributs aurait changé.
Je ne sais pas si cela répond à ta question, mais voici une solution:

class A
{
public:
  A(int id)
    : _id(id)
  {
  }
  int getId() const
 {
    return _id;
 }
private:
  const int _id;
};

Tu peux alors faire :

Prog.a = new A(4);

Etait-ce bien là ta question ?
Messages postés
966
Date d'inscription
samedi 3 avril 2004
Statut
Membre
Dernière intervention
4 mars 2010
4
tu peux aussi passer par une fonction de création personnalisée :

class A1;
// ...

class A
{
// ...
static A* new_instance(unsigned iType);
};

class A1 :public A
{
// ...
};

A* A::new_instance(unsigned iType)
{
switch(iType)
{
case 1: return new A1();
case 2: return new A2();
// ...
}
}

de même pour B, C, D...

donc tu pourras par la suite :
Prog.a=A::new_instance(4);
Prog.b=B::new_instance(6);
// ...
Messages postés
4
Date d'inscription
dimanche 12 juillet 2009
Statut
Membre
Dernière intervention
13 juillet 2009

@CptPingu: Non, ce n'est pas ce que je veux faire.
@juju12: Je ne veux pas de switch ; c'est acceptable pour quelques cas mais j'en aurais des centaines!

Je vais donner un exemple plus clair et plus précis:

class Security {
// code
};

class Encryption: public Security {
// code
};

class Authentication: public Security {
// code
};

class Transmission {
// code
};

class Connected: public Transmission {
// code
};

class ConnectionLess: public Transmission {
// code
};

///
class Prog {
Security *sec;
Transmission *trans;

...
};

int main() {

// demande à l'utilisateur de choisir le type de sécurité et de transmission

sec = new ???
trans = new ???
}

L'utilisateur verra sur son terminal:
Quel type de sécurité: 1- Encryption 2- Authentication
Quel type de transmission: 1- Connected 2- ConnectionLess

Je voudrais instancier les classes que l'utilisateur aura choisies.
Messages postés
3829
Date d'inscription
dimanche 12 décembre 2004
Statut
Modérateur
Dernière intervention
8 janvier 2021
114
La solution donné par juju12 (voir design pattern factory) me semble dans ce cas, la seule adaptée.
Dès le moment ou l'utilisateur fait un choix, il faut bien l'analyser, et donc il y aura des tests conditionnels.
Messages postés
4
Date d'inscription
dimanche 12 juillet 2009
Statut
Membre
Dernière intervention
13 juillet 2009

Je pensais à une solution comme une std::map avec pour chaque entrée, un entier en guise de clé et pour la valeur correspondant à la clé "quelque chose". Mais quoi? En Java, j'aurais pu mettre le nom de la classe car on peut créer une instance d'une classe à partir de son nom. Je n'ai pas dit ça plus tôt pour ne pas influencer les réponses. Il me faudrait une sorte de pointeur sur classe...
Il doit bien y avoir une façon de référencer une classe. Ainsi, avec une map, il suffit de chercher le choix de l'utilisateur - mymap.find(choice) - soit une ou deux lignes de code, au lieu de 100 lignes pour un switch avec 100 possibilités. En plus, si quelqu'un veut ajouter une possibilité, il n'aura pas besoin de toucher au code si je lui fournis une fonction permettant d'ajouter une entrée dans la map...

Je ne sais pas s'il est possible de s'en sortir avec une map STL ? ou avec une autre conteneur ? ou un conteneur personnalisé ?
Messages postés
4
Date d'inscription
dimanche 12 juillet 2009
Statut
Membre
Dernière intervention
13 juillet 2009

Parfait, c'est ce qu'il me fallait.
Je ne connais que très peu les templates, je vais étudier ça de plus près...
Merci beaucoup pour ton aide CptPingu.