8
votes

Pourquoi les fonctions virtuelles doivent-elles être transmises avec un pointeur et non par la valeur (de l'objet)?

Je pense que je comprends le concept de méthodes virtuelles et de vtales, mais je ne comprends pas pourquoi il y a une différence entre le passage de l'objet comme un pointeur (ou une référence) et le transmettre par la valeur (quel type de gaspillage quelque chose?)

Pourquoi quelque chose comme ce travail: p> xxx pré>

et pas ceci ?: p>

Material m = Texture();
poly->setMaterial(m);
// methods from Material are called if I pass the value around


3 commentaires

Qu'est-ce que poly et qu'est-ce que cela a à voir avec quelque chose? Où sont vos appels virtuels actuels? Comment se fait-il que votre méthode SetMaterial peut accepter les deux pointeurs et les valeurs? Est-ce surchargé?


@Andreyt Ce n'était pas vrai code que je viens d'écrire deux exemples potentiels.


Génial, mais votre question concerne les appels virtuels. Pourtant, vos exemples (peu importe réels ni artificiels) n'incluent aucun appels virtuels pertinents du tout.


7 Réponses :


1
votes

Une fois que vous avez attribué un objet de texture à un matériau, il est tranché à un matériau. Par conséquent, tout appel sur l'objet M n'abandonnera que les fonctions matérielles.

matériau M a de l'espace pour exactement un objet de matériau.

Utiliser des structures simples, j'illeure ce qui est signifiait par trancher: xxx


0 commentaires

4
votes

matériau m = texture () appellerait le constructeur matériau :: matériau (texture const &) ou, si cela n'est pas disponible, le matériel < / Code> Copie Constructeur, qui construit un matériau plutôt que par une texture .

Il n'y a aucun moyen de construire un objet texture pour vous, de sorte que l'objet est tranché à un objet de classe de base.


5 commentaires

Malgré le signe = , il n'y a pas d'affectation dans type foo = bar;


@Frederverflow: Vous avez raison, corrigé cela. Je pensais qu'il y aurait si matériau n'a pas de constructeur de copie.


Petite correction: matériau m = texture () appellerait le constructeur matériau :: matériau (texture const &) ou defalut constructeur matériau :: matériel () Puis opérateur d'affectation matériau :: opérateur = (texture const &)


@Mihran hovsepian: Non. Il n'y a jamais d'affectation ici. Essayez-le.


@Mihran: En fait, ça ne le fait pas. Essayez de définir matériau avec CORTOR par défaut et opérateur = mais copie privée cors.



19
votes

Parce que si vous passez de valeur, alors Tranchement d'objet se produira et le polymorphisme d'exécution ne peut pas être atteint. Et dans votre code, la ligne même matériau m = texture () code> provoque la tranchée d'objet. Donc, même si vous passez m code> par pointeur (ou référence), le polymorphisme d'exécution ne peut pas être atteint.

En outre, le polymorphisme d'exécution est réalisé à travers: p>

  • Pointeur de type de base, ou li>
  • Référence du type de base li> ul>

    Donc, si vous voulez un polymorphisme d'exécution, vous utilisez le pointeur em> ou référence em> du type de base, et voici quelques exemples comment vous pouvez atteindre le temps d'exécution POLYMORPHISME: P>

    Material* m1 = new Texture();
    poly->setMaterial(m1);     //achieved
    
    Texture* t1= new Texture();
    poly->setMaterial(t1);     //achieved
    
    Texture t2;
    poly->setMaterial( &t2);   //achieved : notice '&'
    
    Material & m2 =  t2;
    poly->setMaterial( &m2 );  //achieved : notice '&'
    
    Material  m3;
    poly->setMaterial( &m3 );  //NOT achieved : notice '&'
    


7 commentaires

+1: la question si elle n'est pas 100% claire pour moi. Mais c'est aussi ma conclusion.


Merci, c'est probablement ce qui se passait dans mon code. La deuxième phrase de l'article Wiki était tout à fait la révélation: "Depuis que la superclasse n'a aucun endroit pour les stocker [les attributs de l'enfant]".


Je ne comprends pas votre déclaration. Que voulez-vous dire par écrit "Atteindre"? SetMaterial fonctionnera pour tous les matériau Hiérarchie due au sous-type polymorphisme. Le polymorphisme est une propriété de setmaterial , il vaut mieux dire "employé". Si nous disons que le polymorphisme ici est une capacité de travailler avec différents types qui ont une interface , puis chaque getmaaterial invoke utilisera le polymorphisme (puisque matériau La classe elle-même implémente son interface)


@RIGA: Par "Atteindre" Je voulais accéder à Texture à l'aide du pointeur de type matériau * .


@Namaz, non, vous avez écrit "Atteindre le polymorphisme d'exécution", votre dernière déclaration "non réalisée" n'est pas correcte car le polymorphisme est obtenu en prenant un objet qui implémente une interface matériau à chaque fois. Comme vous l'avez indiqué précédemment, la fonction n'obtient pas un objet lui-même, mais un pointeur ou une référence. Cela fonctionne avec ce pointeur avec succès, le polymorphisme est utilisé.


@RIGA: Avez-vous lu ce que je voulais dire par "Atteindre le polymorphisme d'exécution"?


@Nawaz, Oh! Je vois! bool opérateur == (const obj & o1, const obj & o2) {retour o1! = O2; } c'est bon! Tu voulais juste quelque chose de différent! Approche solide.



2
votes

parce que matériau m = texture (); tranches l'objet - à ce stade, vous avez simplement un matériau . .


0 commentaires

1
votes
Material m = Texture();
This create a temporary Texture, then creates a Material by copying the Material part of Texture. This is called slicing, and is typically not what you want.

1 commentaires

Il ne construit pas et copie ensuite; Il appelle le constructeur de copie.



3
votes

Les fonctions virtuelles fonctionnent parfaitement dans vos deux exemples. Ils travaillent exactement comme ils sont censés travailler.

L'idée de la fonction virtuelle est qu'un appel à une telle fonction est expédié conformément au type dynamique de l'objet utilisé dans l'appel. (Malheureusement, vous n'avez pas montré dans vos exemples comment vous effectuez ces appels.)

Dans votre premier exemple, vous avez créé un objet de type texture . Le type dynamique de l'objet est texture , de sorte que les appels virtuels vont aux méthodes de texture .

Dans le second cas, vous créez un objet de type matériau . Le type dynamique de l'objet est matériau , de sorte que les appels virtuels vont aux méthodes de matériau .

C'est tout ce qu'il y a. Tout fonctionne comme on peut s'attendre. Si vos attentes sont différentes de ceci, vous devriez simplement les apporter d'un meilleur alignement avec la langue.


7 commentaires

Je pense que le problème dans le deuxième exemple est qu'une texture sera tranchée dans un matériau sur la construction de la copie. Ainsi, toutes les fonctions virtuelles appelées sur m ne fonctionneront pas (comme un débutant attendu).


@Martin: Non. Le problème est que l'objet créé dans le deuxième exemple a le type matériau . Période. "Tranking" dans ce cas est complètement à côté du point. "Tranking" se produit pendant l'initialisation du nouvel objet. L'initialisation n'a pas d'importance. L'OP crée un objet de type matériau - c'est la seule chose qui compte. Comment l'OP tente d'initialiser cet objet (avec «tranchant» ou sans) est totalement non pertinent.


Totalement en désaccord. Ils créent un objet de texture de type. Au moment où ils appellent des méthodes virtuelles, il n'est plus une texture, mais un objet important (c'est-à-dire le creux du problème). Ils obtiennent un matériel parce que la texture a été tranchée. Donc, le code fonctionne comme on pouvait s'y attendre. Le problème est que cela ne fonctionne pas car l'OP s'attend à ce que leur objet a été tranchée.


@Martin: non pertinent. Le deuxième code crée un objet nommé M de type matériau et un objet temporaire de type texture . Les appels virtuels sont effectués via l'objet M de type matériau . Le type de type texture ne participe en aucun cas à des appels virtuels (cela ne peut tout simplement pas), c'est pourquoi il est totalement non pertinent. Les appels, encore une fois, sont effectués via m , qui est matériau . C'est la seule chose qui compte. Le fait que ce m a été initialisé avec texture () n'aime pas du tout. Le type de l'objet est ce qui compte. Comment cela a été initialisé est hors de propos.


@ Andreyt: Cela le rend hors de propos du système de course. Mais c'est ce fait exact qui en fait le la partie pertinente de la réponse. En fait c'est la réponse. C'est la seulement une partie de la réponse qui compte vraiment. Tout le reste n'est pas pertinent.


@Martin: Je ne suis pas d'accord. C'est en fait la raison pour laquelle l'OP a rencontré cette confusion en premier lieu: l'OP supposait que l'objet temporaire de la texture affectera en quelque sorte le comportement dynamique de l'objet final objet . En réalité, ce n'est pas le cas. La tranchée a effectivement lieu lors de l'initialisation de l'objet matériau . Cependant, depuis que la mise au point de cette question est le comportement virtuel, il est très important d'insister sur ce qui compte vraiment: le comportement virtuel dépend du type de l'objet et de rien d'autre. Tout le reste est à côté du point.


@Andrett: Oui c'est tout sur le comportement virtuel. Le comportement virtuel ne s'est pas produit à cause de la tranchée. Donc, l'erreur est le résultat de la tranchée qui a provoqué un changement de type inattendu. La tranchée a provoqué l'erreur afin que le tranchage soit le point. Si l'OP ne comprend pas que le tranchant s'est produit, ils répètent plus que probablement l'erreur.



1
votes
class Base
{
    //Members       
};

class Derived1:public Base
{
    //Members
};

int main()
{
    Base obj1;
    Derived1 obj2;

    obj1 = obj2;   //Allowed Since Public Inheritance 
}
When obj1 = obj2 only those members of the Derived Class obj2 that are inherited from Base Class get copied in to obj1, rest of the members of Derived Class get sliced off. This is simply because Base class obj1 is not aware of members of Derived class. This phenomemon is called Object Slicing.In your case, when you call Material m = Texture() only contains members of Material and hence any function call on the object calls member functions of Material& not Texture.

0 commentaires