30

Bah pour la ligne 2, le fait qu'il y ait des fonctions virtuelles n'est pas impliqué, la résolution de la fonction est statique.
Donc absolument aucun changement ^^

Et sinon, si tu fais du développement objet, tu ne peux pas te passer des fonctions virtuelles, dès que tu commence à manipuler des pointeurs. Déjà, rien que le destructeur qui doit être virtuel si tu ne veux pas aller au devant de gros ennuis.

31

hum, j'ai deja fait du devellopement objet, et les fonctions virtuelles je n'ai jamais eu besoin de les utiliser
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

32

Ben c'est dommage pour toi... C'est fort pratique.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

33

Godzil> Tu n'as jamais fait d'héritage alors ? Ou toute tes classes dérivées étaient simples (pas d'allocation dynamique de ressources) ?

34

Si j'ai deja fait de l'héritage et si j'ai deja fait de l'alloc dynamique de ressources, et non je n'ai jamais eu de soucis. J'ai surement du avoir de la chance.
Ca n'empeche que j'aime pas trop la notion de fonction virtuelle propre au C++ (et parlont pas des classes virtuel abstraites, c'est le genre de trucs ou sur des cours de C++, tout le monde est largé, jusqu'a souvent meme le prof, tellement c'est complexe a faire comprendre l'interet)
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

35

mhmmmmmmmm vive les classes virtuelles pures wink

36

Godzil :
(et parlont pas des classes virtuel abstraites, c'est le genre de trucs ou sur des cours de C++, tout le monde est largé, jusqu'a souvent meme le prof, tellement c'est complexe a faire comprendre l'interet)

Bah si, c'est l'équivalent des interfaces en Java, c'est important what
(sauf qu'on peut souvent s'en sortir sans grâce aux templates, mais si on veut éviter les templates, c'est la seule solution)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

37

Godzil
: Ca n'empeche que j'aime pas trop la notion de fonction virtuelle propre au C++ (et parlont pas des classes virtuel abstraites, c'est le genre de trucs ou sur des cours de C++, tout le monde est largé, jusqu'a souvent meme le prof, tellement c'est complexe a faire comprendre l'interet)
Euh non, moi dans mon cours de programmation objet, le prof était très à l'aise avec son sujet...
Et moi je ne pense pas avoir été largué, ni la plupart de mes camarades.
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »

38

pencil

Je vois meme pas ce qu'il y a de compliquer la dedans...

39

Si j'ai deja fait de l'héritage et si j'ai deja fait de l'alloc dynamique de ressources, et non je n'ai jamais eu de soucis. J'ai surement du avoir de la chance.
Si t'appelles "chance" un memory leak qui passe inaperçu, alors oui tu as eu de la chance grin

Consdière l'exemple suivant :
class Base {
public:
    Base()  { cout <<"Base()"  <<endl; }
    ~Base() { cout <<"~Base()" <<endl; }
};

class Derivated : Base {
    int * table;
public:
    Derivated(int x) { cout <<"Derivated(int)" <<endl; table = new int[x]; }
    ~Derivated()     { cout <<"~Derivated()"   <<endl; delete [] table; }

    int & item(int i)       { return table[i]; }
    int   item(int i) const { return table[i]; }
}

Voici maintenant le programme principal :
int main()
{
    Base * X = new Derivated(42);
    delete X;
}


Voyons maintenant la sortie de ce programme =>
Base()
Derivated(int) ~Base()

Et mainetnant, la sortie du même programme, si les destructeurs avaient été virtuels =>
Base()
Derivated(int)
~Derivated() ~Base()


Est-il nécessaire de préciser davantage ?
Cet exemple a une "chance" de 42 octets...

40

Ceci étant dit, cela peut être volontaire de ne pas le mettre virtuel wink

41

Pas sur un destructeur. Sauf à vouloir faire des truc alambiqués délibérément, du genre récupérer le pointeur avant par un autre moyen et le supprimer après en faisant exprès de semer la confusion dans l'esprit de ceux qui regarderons le code....mais faut vraiment le vouloir, et à part l'obfuscation ça n'a aucun intérêt.

42

Bon c'est vrai que jouer sur le destructeur n'est pas forcement tres gentil pour ceux qui relisent le code apres wink

43

spectras :
Est-il nécessaire de préciser davantage ?
Cet exemple a une "chance" de 42 octets...

Ah non, de 42*sizeof(int) octets tongue

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

44

Woups ^^

45

Et on dit Derived, pas Derivated tripo

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

46

Oué c'est ce que je me suis dit avant de poster, puis j'ai eu la flemme de changer grin

47

Et tu as oublié de faire retourner qqch à main tripo

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

48

C'est pas obligatoire, si tu précises pas c'est équivalent à return 0

49

Ah oui, tu m'apprends qqch là happy (mais c'est un peu gore, entre nous soit dit... ça veut dire que si je fais #define main plop et que je définis le vrai main() par "return plop();", le programme pourra se comporter différement fou)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

50

Pollux: ou pour les interface, en java, C# ou Objectve C, mais l'énorme différence, ce que les Interfaces sont clairement définie, et ne sont pas un gros bricolage comme le C++ peut le proposer.
int main() 
{ 
    Base * X = new Derivated(42); 
    delete X; 
}

Ton exemple souleve peut-etre un probleme, mais si tu doit instancier un Derivated avec comme "type" Base, c'est peut etre que ton code déjà à la base a un problème.

faire un truc du genre

void function(Base *X);

int main()
{
 Derivated *X = new Derivated(42);
 function(X);
 delete(X);
}


La Ok, c'est un comportement interessant de l'héritage. "Base *X = new Derivated(42)" n'est pas foncierement un comportement interessant, vu que ton code dépend de Derivated, donc creer un Derivated pour n'utiliser que ça version en "classe mere" l'interet est fortement limité, vu que tu (sans transtyper) ne peut pas utiliser directement ce que propose la classe Derivated


Pour le "return 0" ça doit etre spécifique au C++ (voir meme peut-etre a g++) parce que généralement on obtiens un wanrning "a non void function should return a value" et les valeurs qu'on obtients sonts souvent incohérentes.
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

51

Godzil
: Pollux: ou pour les interface, en java, C# ou Objectve C, mais l'énorme différence, ce que les Interfaces sont clairement définie, et ne sont pas un gros bricolage comme le C++ peut le proposer.

Un gros bricolage confus Au contraire, C++ est nettement plus général, et les interfaces ne sont pas implémentées comme un cas spécial... (même si du coup l'ABI est pas mal plus lourde à cause de l'héritage multiple)
Et si tu ne veux pas te servir de cette généralité, ne t'en sers pas ^^

int main() 
{ 
    Base * X = new Derivated(42); 
    delete X; 
}

Ton exemple souleve peut-etre un probleme, mais si tu doit instancier un Derivated avec comme "type" Base, c'est peut etre que ton code déjà à la base a un problème.

faire un truc du genre

void function(Base *X);

int main()
{
 Derivated *X = new Derivated(42);
 function(X);
 delete(X);
}

La Ok, c'est un comportement interessant de l'héritage.

Oui, mais ce qu'écrit spectras est juste un test case pour souligner uniquement l'essentiel, pas un exemple real-world de ce pourquoi l'héritage est utile...
Pour le "return 0" ça doit etre spécifique au C++ (voir meme peut-etre a g++) parce que généralement on obtiens un wanrning "a non void function should return a value" et les valeurs qu'on obtients sonts souvent incohérentes.

Ben oui, c'est un ajout de C++, mais je connaissais pas smile

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

52

Godzil :
et parlont pas des classes virtuel abstraites
Euh personnellement j'ai jamais fait de C++ mais a priori l'idée d'une classe virtuelle abstraite est plus simple pour moi que celle d'une classe virtuelle pas abstraite (cf. mon post précédent d'ailleurs ^^). D'ailleurs si je ne m'abuse et à moins que j'aie vraiment mal compris, une classe abstraite est forcément virtuelle non ? (parce que si les méthodes n'ont pas d'implémentation et qu'elles ne sont pas remplacées par les méthodes des classes filles qui contiennent l'implémentation, il risque d'y avoir un petit problème cheeky).
En fait moi ce qui me semble bizarre dans votre truc c'est le contraire : les méthodes non virtuelles. Alors c'est sûrement utile, mais d'un point de vue orienté-objet ça me semble surprenant quand même : ça veut dire que truc.bidule() et ((machin)truc).bidule() ne font pas la même chose, c'est bien ça ? alors d'un point de vue C ça se comprend, je suis d'accord (ie ça se comporte exactement pareil que les structures en C), mais d'un point de vue orienté-objet c'est assez spécial (le type avec lequel tu vois l'objet ne devrait représenter qu'une interface qui te dit quels messages tu peux envoyer à cet objet, et après c'est l'objet et lui seul qui décide quelle implémentation correspond aux messages qu'il reçoit ; le fait qu'un même message puisse avoir des effets différents quand tu ne passes pas par la même interface me paraît assez contradictoire avec ça)

avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

53

Oui, "moralement" je sais pas si ça peut avoir un usage propre (où il y aurait des classes héritées avec des fonctions non-virtuelles qui ont une sémantique vraiment différente), mais c'est utile parce que ça n'impose pas de passer par la virtual function table, et donc ça permet l'inlining... Si vector::size() était virtuelle (et donc non-inlinable), ça imposerait une grosse pénalité sur "for (size_t i=0; i<v.size(); i++)", parce qu'il faudrait non seulement appeler la fonction, mais en plus le faire à chaque tour de la boucle parce qu'on ne sait pas que la taille reste constante sick

Donc en gros c'est une optimisation de performance qui sert quand :
- on ne compte pas faire de classes dérivées
- on compte faire des classes dérivées, mais dont l'héritage ne sera pas public (d'ailleurs l'exemple de spectras a encore un bug, il n'hérite pas publiquement de la classe Base, donc il n'a pas le droit de passer de Derived* à Base* tongue) : ça permet par exemple de définir ta propre classe basée sur std::vector, mais avec des méthodes différentes
- on compte faire des classes dérivées et éventuellement redéfinir cette fonction, mais on sait que la fonction définie dans la classe de base sera toujours correcte (mais pas forcément optimale), par exemple
class Base {
    bool is_enabled;
public:
    bool enabled() const {
        return is_enabled;
    }
};
class Derived : public Base {
public:
    Derived() : is_enabled(true) {}
    bool enabled() const {
        return true;
    }
};

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

54

Sally: je parlais pas de moi personnelement (meme si on s'en fou, et meme si j'ai perdu car pas trop pratiqué ce genre de choses) mais je vois les personnes qui étaient autour de moi et qui était juste sur le concept objet, et qui quand on a parlé de virtuel et d'abstrait on été completement largé
avatar
Proud to be CAKE©®™


GCC4TI importe qui a problème en Autriche, pour l'UE plus et une encore de correspours nucléaire, ce n'est pas ytre d'instérier. L'état très même contraire, toujours reconstruire un pouvoir une choyer d'aucrée de compris le plus mite de genre, ce n'est pas moins)
Stalin est l'élection de la langie.

55

truc.bidule() et ((machin)truc).bidule()
Non, puisque le second code est équivalent à
{
    machin temp(truc);
    temp.bidule();
}


Le polymorphisme, c'est un truc qui se fait sur des pointeurs. Alors si on refait avec =>
truc->bidule() et ((machin*)truc)->bidule()
Là justement si ça appelle la même fonction. A condition qu'elle soit définie virtuelle.
Note quand même : ((machin*)truc) => ce code est erroné. Il faut écrire static_cast<machin*>(truc)
Tu risques plein de bugs étranges sinon, parce que l'adresse de la classe de base machin dans l'objet truc n'est pas forcément l'adresse de l'objet truc lui-même.

56

spectras :
Le polymorphisme, c'est un truc qui se fait sur des pointeurs.

... ou bien des références : truc.bidule() vs ((machin&)truc).bidule() ^^

spectras :
Note quand même : ((machin*)truc) => ce code est erroné. Il faut écrire static_cast<machin*>(truc)
Tu risques plein de bugs étranges sinon, parce que l'adresse de la classe de base machin dans l'objet truc n'est pas forcément l'adresse de l'objet truc lui-même.

Euh j'ai l'impression que tu pipotes complètement, pour le coup... si truc est un derivedmachin*, static_cast<machin*>(truc) et (machin*)truc sont rigoureusement équivalents ^^ (et heureusement, t'imagines le carnage qu'il y aurait avec les conversions automatiques quand tu as de l'héritage multiple ? couic)
La différence, c'est que static_cast<> ne change pas le statut "const ou pas", et qu'il est plus restreint puisqu'il ne fera pas de reinterpret_cast<> si le static_cast<> n'est pas applicable... Rien à voir avec les adresses physiques, qui peuvent être ajustées dans les deux cas smile

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

57

Euh pardon, je ne connais pas le C++ et j'ai utilisé la syntaxe java, mais je pensais bien au cas où on manipule des références oui happy
spectras :
Là justement si ça appelle la même fonction. A condition qu'elle soit définie virtuelle.
Oui j'ai bien compris, mais ma remarque portait précisément sur le cas où les fonctions ne sont *pas* virtuelles ^^ (« En fait moi ce qui me semble bizarre dans votre truc c'est le contraire : les méthodes non virtuelles. »)
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

58

spectras :
Coup de bol (ou non, selon le point de vue), la classe complex définit un opérateur de conversion implicite depuis le type double.

Donc si ce n'était pas le cas on aurait pas pu compiler ? C'est marrant parce qu'en Java toute les surchages de toute la hiérarchie sont toujours accessibles.

59

Godzil :
Pollux: ou pour les interface, en java, C# ou Objectve C, mais l'énorme différence, ce que les Interfaces sont clairement définie, et ne sont pas un gros bricolage comme le C++ peut le proposer.
int main() 
{ 
    Base * X = new Derivated(42); 
    delete X; 
}

Ton exemple souleve peut-etre un probleme, mais si tu doit instancier un Derivated avec comme "type" Base, c'est peut etre que ton code déjà à la base a un problème.

faire un truc du genre

void function(Base *X);

int main()
{
 Derivated *X = new Derivated(42);
 function(X);
 delete(X);
}


La Ok, c'est un comportement interessant de l'héritage. "Base *X = new Derivated(42)" n'est pas foncierement un comportement interessant, vu que ton code dépend de Derivated, donc creer un Derivated pour n'utiliser que ça version en "classe mere" l'interet est fortement limité, vu que tu (sans transtyper) ne peut pas utiliser directement ce que propose la classe Derivated


Pour le "return 0" ça doit etre spécifique au C++ (voir meme peut-etre a g++) parce que généralement on obtiens un wanrning "a non void function should return a value" et les valeurs qu'on obtients sonts souvent incohérentes.

C'est marrant, dans mon cours sur les collections en java, on nous a justement dit d'utiliser
List myList = new ArrayList();
Justement pour être sûr que l'interface ne changerait pas, et qu'il suffit de modifier une ligne pour changer l'implémentation...
avatar
Maintenant j'ai la flemme de garder une signature à jour sur ce site. Je n'ai même plus ma chaîne Exec sous la main.

60

pencil
avatar
« Quand le dernier arbre sera abattu, la dernière rivière empoisonnée, le dernier poisson capturé, alors vous découvrirez que l'argent ne se mange pas. »