Partage

comment organiser le programme pour eviter ca:

Sujet résolu
18 août 2018 à 18:52:28

Ceci est un message de débutant.ne vous fachez pas.

J ai un programme avec une classe mere fonction.

elle n a qu un attribut nom

et qu une methode nom()  (l assignment)

deux classes filles fourier et polynomes

elles n ont que la methode de parametrage des coefficient par une methode qui prend un

.  vector de double pour les polynome

.  et un tableau de taille 2 de vector de double pour les fourier.

ainsi qu une redefinission de l operateur () pour rendre un résultat numérique.

Dans le main j ai un tableau de pointeurs de fonction.

vector<Fonction*> funk;

funk.push_back(new polynome());

funk.push_back(new Fourier());

évidemment en l etat..quand je fais funk[0]->setWeight(tab); ou tab esl la donnée qu il faut pour assigner ses valeurs a mon polynome,

vu que le pointeur est un pointeur de fonction il me dit que la methode setWeight n est pas connue dans ce contexte.

du coup est ce que je dois trouver une autre facon d organiser mon programme ou est ce qu il y a une facon magique de faire réaliser au compilateur que c est l addresse d un polynome qu il garde précieusement ?ou encore est ce que du fait que je l ai déclarer comme un pointeur de polynome il n a gardé que les données de la classe fonction lors de l assignation?

si le besoin se fait sentir de lire le code(mais je pense que vous comprenez parfaitement le probleme)je peux le poser.

-
Edité par GouyFred 18 août 2018 à 18:54:09

Vous êtes demandeur d'emploi ?
Sans diplôme post-bac ?

Devenez Développeur web junior

Je postule
Formation
en ligne
Financée
à 100%
18 août 2018 à 20:44:53

Salut,

La première question que tu dois te poser est : y a-t-il du sens à permettre à une fonction polynome et à une fonction Fourrier de "cohabiter" dans une "collection de fonctions"?

Ce que je veux dire par là c'est : ne serait il pas "plus intéressant" d'avoir une donnée de type "polynome" quand tu as besoin de calculer des polynomes et une donnée de type "Fourrier" lorsque tu as besoin d'utiliser la loi de fourrier?  Et, si tu as besoin des deux, ben, "simplement" de prévoir une donnée de chaque type?

En un mot comme en cent: est-il vraiment judicieux que les différentes données représentant ces fonctions puisent être "mélangées"  dans la collection au gré de l'ordre dans lequel on les y aura placées?

Si tu me répond "oui" à la première et à la troisième question, alors, il peut effectivement être judicieux d'envisager de faire hériter tes classes Fourrier et Polynome de ta classe de base Function.  Mais, autrement, cet héritage n'a pas vraiment lieu d'être ;)

Ensuite, si tu as estimé que l'héritage était utile, il va falloir commencer par trouver les "points communs" aux différentes fonctions (car je présumes que tu prévois surement d'avoir d'autres fonctions qui s'ajouteront par la suite :D)

Le seul véritable point commun que je vois est sans doute que l'on peut demander d'effectuer le calcul, et, sans doute, d'espérer obtenir en retour un "état de réussite" (comprends : savoir si la fonction a pu calculer correctement son résultat ou s'il y a "eu un os").  Comme nous sommes bien d'accord sur le  fait que l'exécution du calcul dépendra justement du type de la fonction que l'on veut exécuter, nous devrons donc prévoir un comportement polymorphe "bool execute()" (ou "bool compute()" au niveau de la classe de base, ce qui nous permettrait d'avoir un code proche de

class Function{
public:
   /* Ce qu'il faut pour assurer la sémantique d'entité */
   Function() = default;
   Function(Function const &) = delete;
   Function & operator=(Function const &) = delete;
   virtual ~Function() = default;
   /* Le point commun à toutes les fonctions que nous créerons
    * elles peuvent effectuer "un calcul"
    */
    virtual bool compute() = 0; // tant qu'on ne sait pas
                                // à quelle fonction on a
                                // affaire, on ne peut pas
                                // définir ce comportement
};

Et nous pourrons donc faire hériter nos classes Fourrier et Polynome sous une forme qui serait proche de

class Fourrier : public Funciton{
public:
   bool compute() final override{
       /* ce qui doit être fait
        * renvoie true si ca se passe bien
        * renvoie false si ca coince
        */
   }
   /* ...
    * il y a sans doute des fonctions spécifiques intéressantes
    * pour appliquer la loi de fourrier
    */
private:
   /* ...
    * les différentes données qui seront nécessaires 
    */
};
class Polynome : public Funciton{
public:
   bool compute() final override{
       /* ce qui doit être fait
        * renvoie true si ca se passe bien
        * renvoie false si ca coince
        */
   }
   /* ...
    * il y a sans doute des fonctions spécifiques intéressantes
    * utiliser une fonction créant un polynome
    */
private:
   /* ...
    * les différentes données qui seront nécessaires 
    */
};

Par la suite, on se rend compte que l'on va vouloir s'attendre à disposer de services très différents selon les fonctions que nous utiliserons.  Par exemple, tu voudras pouvoir fournir des données qui permettront de calculer le poids à ta fonction Polynome, mais, c'est un service que l'on a aucune raison d'attendre de la part de la fonction Fourrier (ou des autres fonctions qui ne manqueront pas d'apparaître par la suite dans ton projet).

On ne peut donc pas se "contenter" d'exposer un comportement polymorphe setWeight dans la classe Function et de le redéfinir dans toutes les classes dérivées, parce que cela irait à l'encontre du LSP : notre classe Function ne peut exposer que les comportements qui sont strictement communs à l'ensemble des classes dérivées.

Manque de bol, à partir du moment où tu veux pouvoir faire cohabiter des Fourrier et des Polynomes dans la même collection, tu ne pourra le faire que sous la forme de (référence ou) pointeur (de préférence intelligent)  vers le type Function.  Et, du coup, tu "perdras le type réel" de tes fonctions: ton tableau ne contiendra que ... des pointeurs (de préférence intelligents) ou des références vers des objets connus comme étant des... Function.

Si tu veux être en mesure de récupérer les informations relatives à une donnée de type Fourrier ou à une donnée de type Polynome à partir du contenu de ton tableau, tu n'aura pas d'autre choix : tu devras sans doute passer par ce que l'on appelle le double dispatch.

L'une des possibilité de mettre ce mécanisme en place est fournie par le patron de conception visiteur, mais c'est un patron qui souffre de quelques limites qui peuvent rapidement devenir ... lassantes ;)

Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
18 août 2018 à 21:14:35

Merci encore une fois.

Je vais arreter de vous abreuvez de questions.

Mais je tiens a m expliquer au moins une fois, sur pourquoi tout ca m a l air aussi etranger alors que le cours tranche assez clairement sur la plus part des points ou je vous taraude.

En fait j ai commencé par javascript, et j ai entendu dire que le c++ etait un langage orienté objet plus performant . d autre part en javascript , a force d utiliser des templates on a rapidement l impression de reciter du texte sans comprendre vraiment ce qui se passe. Alors j ai lu que pour comprendre ce qui se passait sur des langages haut niveau il fallait allé voir du coté de ce qui avait servi a les coder.

du coup vu que les interpreteurs de script des navigateurs sont codés en c/c++ je suis venu.

Mais la premiere phrase qui m a fait comprendre que c etait pas comme ca: quelqu un m a ecrit"c++ n est pas un langage objet il n y a pas de class objet dont tout derive" .

Et plus ca avance plus je sens que ca change tout.par exemple avec un nom de variable on pouvait retrouver un type. c etait magique mais la si on fait une affectation funk.tab_push(new polynome) bim c est deja foutu on a deja perdu les jambes.

Du coup concevoir un programme en javascript ca pouvait se faire avec des mots sans reflechir a l architecture(sauf sans doute pour les performance, mais vu que je suis tout seul sur mon serveur local tout va bien :p) mais la faut penser d un bout a l autre du vaisseau a ce qu on va pouvoir recuperer sans savoir quelles seront les ajouts futurs du programmes.

Je crois qu avec ton explication j ai enfin compris que programmer en c++ c est comme l peche a la crevete(dixit forest gump:p):

C est dur.

Ici si je fais du setParam sur une fonction virtuelle de la classe fonction faut que j indique le type..et du coup ca sert a rien et si je template le type les variables entrantes quand je fais le tableau il me dit qu il faut pas rever et que c est pas la meme classe si j ai templaté la classe et que il faut pas rever c ette fonction est pas du quartier si j ai templater la fonction.

-
Edité par GouyFred 18 août 2018 à 21:34:15

19 août 2018 à 0:01:31

GouyFred a écrit:

du coup vu que les interpreteurs de script des navigateurs sont codés en c/c++ je suis venu.

C'est un aberration de parler conjointement de C/C++ !!! Ce sont deux langage aussi différents que le latin de Jules Cesar et le Francais actuel : Bien sur C++ hérite de C, tout comme le Français est en grande partie issu du latin. Mais tout comme le Français a évolué au point de ne presque plus utiliser le moindre terme latin "tel quel", C et C++ ont suivi des chemins totalement différents, qui font qu'ils n'ont au final plus qu'une partie de la syntaxe en commun.

(et le pire, c'est que c'est cette syntaxe commune se retrouve également en java... Or, on ne dira jamais " je programme en C / java" :D )

GouyFred a écrit:

En fait j ai commencé par javascript, et j ai entendu dire que le c++ etait un langage orienté objet plus performant .

C++ est un langage compilé, alors que javascript est interprété.  Cela donne "naturellement" un certain avantage à C++ en ce qui concerne les performances.  Mais il n'y a rien à faire : un mauvais algorithme codé (ou pire : mal codé) en C++ sera sans doute bien moins performant qu'un bon algorithme (correctement codé) en javascript.

GouyFred a écrit:

D autre part en javascript , a force d utiliser des templates on a rapidement l impression de reciter du texte sans comprendre vraiment ce qui se passe.

On utilise forcément des modèles qui permettent certaines choses, quel que soit le langage considéré.  Et il n'y a rien à faire : si on utilise le même paradigme avec deux langages, il y a fort à parier que nous utiliserons les mêmes modèles pour l'un et pour l'autre.

Les quelques rares différences que nous pourrons rencontrer dans l'utilisation de ces modèles seront le plus souvent dues aux différences de "mentalité" que l'on rencontre entre les deux langages ;)

GouyFred a écrit:

Alors j ai lu que pour comprendre ce qui se passait sur des langages haut niveau il fallait allé voir du coté de ce qui avait servi a les coder.

Humm... je suis (très) loin d'en être convaincu...

Il me semble bien plus intéressant d'essayer de comprendre la "philosophie" qui a présidé à la création du langage que l'on utilise ;)  Par exemple, pour java:

  • Pourquoi ont ils décidé que toute classe hériterait forcément de la classe Object?
  • Pourquoi ont ils décidé de faire la distinction entre les clases et les interfaces?
  • Pourquoi ont il décidé "d'interdire" l'héritage multiple?
  • Mais est ce que java interdit réellement l'héritage multiple, ou n'est ce que de la poudre au yeux?
  • Quel est la différence (ou la similitude) conceptuelle entre le mot clé extends et le mot clé implements (indice : "LSP inside")?
  • Quelle est la différence conceptuelle entre le mot clé class et le mot clé interface?
  • j'en oublie surement ;)

Si tu trouves la "bonne" réponse à ce genre de question, tu arriveras sans doute à te faire une "bonne" idée de la philosophie de java, et tu pourras l'utiliser correctement.

En apprenant un autre langage, comme C++, tout ce que tu pourras arriver à faire, c'est trouver des différences entre la mentalité qui a présidé à la création de C++ et celle qui a présidé à la création de java ;)

GouyFred a écrit:

quelqu un m a ecrit"c++ n est pas un langage objet il n y a pas de class objet dont tout derive" .

Et celui qui t'a écrit cela n'a visiblement rien compris au paradigme orienté objets... A moins qu'il ne se soit très mal exprimé ;)

Il ne faut pas forcément que le langage utilise une classe de base (appelons la comme on veut, Object n'est pas plus mal que n'importe quel autre nom) dont tout dérive pour avoir affaire à un langage orienté objet !

Le principe de l'orienté objet (du moins, tel qu'exposé par java, C# et C++) est d'avoir des objets au départ desquels nous pouvons faire appel à certains services, qui se subdivisent en deux grandes catégories:

  • les questions que l'on peut poser pour se faire une idée de l'état actuel de l'objet et
  • les ordres que nous pouvons lui donner de manière à faire varier l'état de l'objet

Accessoirement, le paradigme orienté objet (du moins, tel qu'exposé par C++, java et C# ) nous permet de mettre en place la substituabilité, telle que décrite par Barbara Liskov et le LSP : si f(x) est une propriété valide pour un objet x de type T, alors f(y) doit être une propriété valide pour l'objet y dont le type S est un sou-type de T.

Et cela se traduit de la même manière dans les trois langages : l'héritage public ;)

En outre, la possibilité d'avoir des sous-type qui "dérivent" ou qui "spécialisent" un type de base nous place souvent face au besoin de pouvoir faire varier certains comportements en fonction du type réel à partir duquel ils sont appelés, ce qui nous mène tout droit à la notion de polymorphisme (d'inclusion, pour être précis).

Et, encore une fois, cela se traduit de la même manière dans les trois langages, bien qu'elle soit implicite (et forcée) en java et en C# : il faut des fonctions pour lesquelles il soit possible de redéfinir le comportement dans les classes dérivées.  Ce qui est explicitement demandé (en C++) au travers du mot clé virtual ;)

GouyFred a écrit:

Du coup concevoir un programme en javascript ca pouvait se faire avec des mots sans reflechir a l architecture(sauf sans doute pour les performance, mais vu que je suis tout seul sur mon serveur local tout va bien :p) mais la faut penser d un bout a l autre du vaisseau a ce qu on va pouvoir recuperer sans savoir quelles seront les ajouts futurs du programmes.

Il faut bien comprendre que C++ est un langage particulièrement complexe, dont la philosophie de base est:

  1. le développeur ne doit payer le surcoût que de ce qu'il utilise (pas de virtualité forcée, pas de classe "God object", pas de machine virtuelle... si on n'en a pas besoin) et
  2. On privilégie la fonctionnalité au risque d'erreur. Si une possibilité est "dangereuse" mais mais qu'elle présente une certaine utilité, on la fournit pour son utilité : au développeur de veiller à l'utiliser correctement

De plus, c'est un langage qui propose nativement trois paradigmes parfaitement intégrés les uns par rapport aux autres.  Et il n'est donc pas rare de croiser des projets qui mélangent allègrement le paradigme purement procédural, le paradigme générique et le paradigme orienté objets (et on peut même y trouver une certaine forme de programmation fonctionnelle :D ) en fonction des besoins à rencontrer.

Bien sur, la liberté que cela peut nous apporter a un prix car on en arrive donc très rapidement à un point où le développeur doit asseoir les bases de son projet sur une conception particulièrement rigoureuse, car le langage ne mettra que très peu de "gardes fou" du point de vue conceptuel, et que tous les aspects qui  n'auront pas fait preuve d'une conception correcte au préalable risqueront -- au mieux-- de dégénérer en dette technique importante, au pire, d'être sources d'erreurs et d'impossibilité d'évolution par la suite.

Mais, l'un dans l'autre, si on comprend et qu'on est capable de respecter les principes SOLID et la loi de Déméter, et que -- de plus -- on comprend l'utilisation qui peut être faite des différents patrons de conception, on est très certainement déjà paré pour pouvoir faire face à la très grosses majorité des situations que nous pourrions rencontrer:

La syntaxe n'est pas plus compliquée que celle de java, et la véritable difficulté est d'arriver à se rendre compte de tout ce qu'il y a moyen de faire en utilisant le paradigme générique (qui est sans doute le paradigme les moins bien documenté des trois) ;)

Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
20 août 2018 à 16:24:35

Quelques remarque, Contrairement à JAVA et comme le C++, en C# les méthodes ne sont pas virtuelles par défaut.

@koala01, tu références JAVA, mais il faut bien voir que, malgré le terme "JavaScript", "JavaScript" est un langage fonctionnel bien plus éloigné de JAVA que n'est éloigné JAVA du C++.

@GouyFred, Si tu as de bonnes connaissances en JavaScript pré ES6, je te conseille de regarder les extensions objets offertes par l'extension ES6 de ce langage.

Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

comment organiser le programme pour eviter ca:

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown