Bonjour gl,
Cela affiche le résultat du calcul.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Et si tu affiches le résultat du calcul dans le main, il se passe quoi ?
Pourquoi cette question?
Bonjour gl,
Cela affiche le résultat du calcul.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 Et si tu affiches le résultat du calcul dans le main, il se passe quoi ?
Pourquoi cette question?
Je parlais en terme de performance.
Pourquoi cette question ?
Tout simplement parce que vu les temps extrêmement faible relevé lors de tes tests avec Visual et puisque le résultat du calcul n'est pas utilisé dans le programme, je soupçonne que le calcul a été purement et simplement lors de l'optimisation lorsque le destructeur n'est pas virtuel.
Bonsoir,
Bien vu gl!Tout simplement parce que vu les temps extrêmement faible relevé lors de tes tests avec Visual et puisque le résultat du calcul n'est pas utilisé dans le programme, je soupçonne que le calcul a été purement et simplement lors de l'optimisation lorsque le destructeur n'est pas virtuel.
Effectivement, en ajoutant l'affichage j'obtiens des temps de calcul raisonnables;
Verdict : les temps sont identiques même en faisant de Number une classe abstraite!
J'imagine que les opérations de destruction sont plus ou moins longues selon les déclarations mais je n'ai pas eu le courage de vérifier.
Mais alors que se passe-t-il avec g++?
J'ai un petit doute sur Netbeans (c'est l'IDE que j'utilise)...
Je vous tiens au courant.
En compilant en -02 ou -03, je n'ai aucune différence significative.
En compilant en -O0, il y a une différence de 50% environ, mais bon, ça n'est pas très important. C'est probablement lié àune différence dans la manière dont gcc génère le destructeur.
Bonjour,
Merci beaucoup d'avoir testé.En compilant en -02 ou -03, je n'ai aucune différence significative.
En compilant en -O0, il y a une différence de 50% environ, mais bon, ça n'est pas très important. C'est probablement lié àune différence dans la manière dont gcc génère le destructeur.
Effectivement, mes tests étaient faux.
La désinstallation de MinGW avec Windows ne fonctionnant pas, il a dû se passer un truc bizarre quand MinGW et TDM-GCC ont coexisté.
Finalement, les temps sont les mêmes quand je déclare le destructeur de Number.
C'est encore vrai quand le destructeur est virtuel.
Par contre, cela redevient très lent quand le destructeur est virtuel pur.
Existe-t-il un moyen de déclarer un tel destructeur inline?
Ouais, quand c'est la seule fonction qu'on peut rendre virtuelle pure dans une classe de base. Mais il faut quand même en fournir une implémentation sinon ca passe pas au linker quand les classes dérivées tentent de l'appeller (appel automatique du destructeur de la classe parente).
Pour comprendre cela, il faut se rappeller qu'une fonction virtuelle est une fonction qu'on peut redéfinir dans les classes dérivées, une virtuelle pure est une fonction qu'on doit redéfinir. De mémoire (pas le temps de vérifier) rien n'est dit sur la présence d'une définition pour une fonction virtuelle pure : elle peut être donnée par le programmeur comme non. Si on donne une définition à une fonction virtuelle pure, c'est par contre forcément en dehors de la classe.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 class A { public: virtual ~A() = 0; }; A::~A(){} class B: public A { };
Bonsoir,
Pas particulièrement.Tu a une bonne raison de garder cet héritage ? A mon avis il t'apporte plus de problèmes qu'autre chose...
En fait, ce n'est pas vraiment mon problème pour le moment.
La question que je me pose est plutôt de savoir si je dois utiliser des classes abstraites.
Avec le compilo de visual je n'ai pas de perte de performances.
Avec g++, j'en ai et c'est problématique.
Maintenant, s'il est possible de représenter les nombres par des classes en changeant de conception et en ne perdant pas en performances je suis preneur.
Les nombres complexes n'étant pas typés en c++, j'ai besoin de faire une classe.
Du coup, je me suis dit qu'il pourrait être bien de faire une classe pour les réels.
En particulier, pour stocker des réels et des complexes dans un même tableau.
J'en ai déduit qu'il fallait que mes deux classes héritent d'une même classe de base : Number.
Ensuite, je me suis dit que je pourrais gagner un peu de temps en codant tout ce qui concerne les réels et les complexes une fois pour toute, quel que soit le dégré de précision de mes calculs.
C'est la raison d'être de la classe Real<T> (et d'une autre classe Complex<T>).
Dans mon esprit, la classe Number n'a pas à être instanciée.
Je me suis naturellement tourné vers une définition de classe abstraite mais je perds en performances.
Pour le moment, je contourne le problème en déclarant les constructeurs comme étant protégés.
D'autre part, la généricité ne me convient pas tout à fait parce que je ne vérifie pas les typenames de mes classes génériques.
Par exemple, Real<double*> n'a pas de sens pour moi.
C'est pour cela que je "force" mes typename par l'héritage.
Par exemple, DoubleReal hérite de Real<double> ET les constructeurs de Real<T> sont protégés.
Si quelqu'un voit une meilleure approche, je suis ouvert!
J'ai un niveau débutant en C++ donc ma conception est sûrement naïve.
Je confirme ce que David a dit.
Le fait de donner une définition à une méthode abstraite permet de définir un comportement de base aux classes fille qui ne saurait comment la redéfinir :
Et comme David l'a signalé, pour un destructeur donner une définition est "presque" obligatoire.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 struct A { void foo() = 0; } virtual void A::foo() { /*code*/ } struct B : A { /*classe fille qui ne sait comment la redéfinir*/ void foo() { A::foo(); } /*utilisation d'un comportement de base*/ };
[HS]Hormis le cas particulier du destructeur (définition obligatoire) qui est parfois le seul moyen de faire d'une classe une classe abstraite, je n'ai pas réussi à trouver un cas pertinent pour donner une définition à une fonction virtuelle pure autre qu'un destructeur. Son appel est toujours selon un type dynamique différent de la classe abstraite puisqu'elle ne peut être instanciée. Cela implique donc un appel explicite de la fonction virtuelle pure de la part de la classe dérivée. Le seul cas où type dynamique et type statique coïncide pour une classe abstraite c'est pendant le constructeur et le destructeur. Mais la norme est formelle : des appels de fonctions virtuelles pures dans le constructeur ou le destructeur des classes abstraites sont des comportements indéterminés (ce qui n'est pas le cas d'une classe concrète spécialisant cette fonction virtuelle pure).
Cf Et pour les fonctions virtuelles pures ?
[HS] Oui je suis d'accord il faut un appel explicite, mais je pense que ce genre de chose peut servir à qulqu'un qui fait une bibliothèque par exemple, et qui offre une classe de base à hériter qui doit être abstraite, définir la fonction virtuelle pure pourrait être un moyen à l'auteur de dire : "Tu veus hériter de ma classe mais tu ne sais pas quoi mettre dans la méthode virtuelle pure ? Appel explicitement celle de la classe mère tu auras un comportement par défaut valide. ". C'est ce que je comprend de l'item 34 de Meyers . Mais bon, ca doit quand même pas servir tout les jours ! Et oui pas question de les utiliser dans les constructeurs/destructeurs [/HS]
Bonjour,
merci pour ton lien Alp.
J'ai mal exprimé ma pensée.
Ce que je veux dire c'est qu'il n'y a pas de type double complex au même titre que double par exemple.
En C++, les complexes ont simplement été standardisés à l'aide d'une classe.
Bonjour,
Je ne trouve pas d'exemple où ce serait nécessaire.
Tu peux expliquer pourquoi?
J'ai l'impression qu'on peut faire des complexes avec des choux ou des carottes (le value_type peut être tout autre chose que float, double ou long double si j'ai bien compris).
C'est justement ce que je veux éviter.
Grâce à ton lien, j'ai par contre appris que les complexes sont également standardisés en C : http://en.wikipedia.org/wiki/Complex.h
Je crois que c'est ce qui se rapproche le plus de ce que je souhaite.
Malheureusement, ça ne résout mon problème de temps de calcul avec g++ et les destructeurs virtuels purs.
J'avais pris la décision de passer à Visual mais maintenant c'est la compilation de Qt qui pose des problèmes!!!
Donc, dans la mesure du possible, je préfèrerais déjà être sûr qu'il faut absolument que j'abandonne g++ pour avoir du code rapide avec des classes abstraites.
Rien que les indices de boucle qui souvent i,j,k, les paramètres des fonctions (T& operator[](int i) ne serait plus possible) ....Je ne trouve pas d'exemple où ce serait nécessaire.
Tu peux expliquer pourquoi?
C'est le but ! Tu as la précision de stockage que tu veux. derrière rien ne t'empèche d'utiliser autre chose que des types natifs si tu en as le besoin.J'ai l'impression qu'on peut faire des complexes avec des choux ou des carottes (le value_type peut être tout autre chose que float, double ou long double si j'ai bien compris).
Bah on te laisse le choix sur la précision via le paramètre template, je ne vois pas où est le problème. Au contraire, je ne vois que des avantages.C'est justement ce que je veux éviter.
En C99, qui n'est pas bien supporté pas grand monde. En C90, ils n'y sont pas.Grâce à ton lien, j'ai par contre appris que les complexes sont également standardisés en C : http://en.wikipedia.org/wiki/Complex.h
Tu peux dire formellement ce que tu veux, car tes questions d'héritage te brouille la vue (AMHA)Je crois que c'est ce qui se rapproche le plus de ce que je souhaite.
Bonjour,
Je ne suis pas bête à ce point!
Ce n'était pas du tout ma question.
En quoi est-il nécessaire de réserver quelque chose pour l'unité imaginaire pure?
En d'autres termes, quel est l'utilité de le différencier d'un autre nombre complexe?
On est d'accord pour la précision.
Pour les reste, il semble que je fasse moins confiance aux utilisateurs de mes codes que toi.
Ah... merci pour l'info, je repasse par la case départ.
J'attends tes critiques alors n'hésite pas!
Pour l'instant, je suis bloqué (enfin presque, je viens de compiler Qt pour Visual )
Tain, je suis décidément pas réveillé ><. Sinon, je rejoins ton avis dessus, en rien. Suffit de créer une structure avec deux membres et les fonctions libres qui vont bien (vu que le C ne supporte pas la surcharge d'opérateur)En quoi est-il nécessaire de réserver quelque chose pour l'unité imaginaire pure?
En d'autres termes, quel est l'utilité de le différencier d'un autre nombre complexe?
je pensais surtout à des choses comme GMP (ou what ever else ) qui peuvent être nécessaires pour représenter un nombre dans certains cas (surtout quand les type natif du C++ ne sont plus suffisants). Au sujet de la confiance, l'utilisation de la classe template impose un "contrat" au paramètre template en terme de fonctionnalités, je ne vois pas de problèmes potentiels.Pour les reste, il semble que je fasse moins confiance aux utilisateurs de mes codes que toi.
Bah disons que certains compilateurs sont plus compatible que d'autres et qu'il a fallu 11 ans au C99 pour arriver là. Le C99 a plutôt mal percé dans la communauté C.Ah... merci pour l'info, je repasse par la case départ.
En l'état actuel (le code du 1er post, je ne crois qu'il ait évolué en parcourant en diagonale les posts), tu as des héritages vide de sens car il n'apportent rien. Une approche transversale (à bas de template "seule") serait sans doute mieux. Mais de toute façon, je ne vois même pas à quoi peut te servir ces classes puisqu'elles n'ont aucune "valeur ajoutée", elles sont aussi vides de sens. Bref, je ne vois pas quoi ca pourrait te servir ou pourquoi tu fais ca.J'attends tes critiques alors n'hésite pas!
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager