Question

J'ai créé une classe, appelée vir, avec une fonction move:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     void move(){}
};

(dérivé d'une classe avec les variables int x, int y et char sym) J'ai dérivé une classe appelée subvir:

class subvir:public vir
{
public:
     subvir(int a,int b,char s){x=a;y=b;sym=s;}
     void move();
};
subvir::move()
{
     x++;
     return;
}

Et puis j'ai créé un tableau de vir et y ai placé un sousvir

subvir sv1(0,0,'Q');
vir vir_RA[1]={sv1};

Mais quand j'essaie d'utiliser sv1.move ():

vir_RA [0] .move ();

Il utilise le vir move ({}) plutôt que le subvir move ({x ++}). J'ai essayé de faire sv1 vir et vir_RA vir, et ça marche, et ça marche aussi quand je les fais tous les deux, mais j'ai besoin qu'ils soient différents. J'ai essayé de transformer vir :: move () en virtuel pur, mais une erreur s'est produite lors de la justification du tableau. Est-ce que quelqu'un sait comment je peux faire fonctionner move () lorsque je l'utilise depuis le tableau?

Était-ce utile?

La solution

Dans ce cas, vous avez besoin d'un tableau de pointeurs plutôt que d'un tableau d'instances. Utilisez vir * [] au lieu de vir []

Autres conseils

Vous rencontrez un problème appelé découpage . Utilisez un tableau de pointeurs, ou quelque chose comme Boost.ptr_container .

La classe de base doit avoir des fonctions virtual pour que vous obteniez ce que vous voulez. En les rendant purs, vous obtiendrez une classe de base abstraite, chose que vous ne pouvez pas instancier. Cependant, vous pouvez toujours créer des pointeurs / références vers des classes de base abstraites et leur affecter des objets de classe dérivés. Votre classe de base est mieux représentée sous la forme:

class vir
{
public:
     vir(int a,int b,char s){x=a;y=b;sym=s;}
     virtual void move(){}
};

Cela rend également le code move de la classe dérivée virtuel. Cependant, votre définition move ne contient pas de valeur de retour et ne sera pas compilée. Essayez:

void subvir::move()
{
     x++;
     return;
}

Notez que vous avez besoin de pointeurs (comme indiqué dans les autres réponses) ou de références à des classes dérivées pour que la liaison dynamique fonctionne. Ainsi, au lieu d’un tableau d’objets vir , utilisez un tableau de pointeurs de classe de base:

vir* v[ 2 ] = { new subvir(0, 0, 'Q'), new subvir(10, -10, 'P') };

Vous devriez aussi f Lisez les sections suivantes de la FAQ Lite sur C ++:

Deux choses. Le tableau est un tableau de vir alors, bien sûr, il utilise vir :: move. move () n'est pas une méthode virtuelle.

Mais le plus important est le découpage en tranches. Vous ne pouvez pas mettre de sous-classes dans un tableau. Si sizeof vir! = Sizeof sousvir, le tableau ne s'alignera pas correctement. Actuellement, ils ont la même taille. Mais que se passe-t-il s’ils ne le sont pas?

Oui, fondamentalement, le compilateur n'autorise pas les sous-classes dans les tableaux car Les tableaux sont initialisés avec précision pour la taille du type, et les sous-types ont tendance à d'être plus grand que les parents et cela poserait des problèmes si vous pouviez initialiser les tableaux avec des valeurs de sous-type. En réalité, le compilateur alloue d’abord le tableau N * taille (base_type) octets. Et puis il copie la taille (base_type) en octets de chaque initialisation objets. s'ils étaient de types différents, ils seraient tronqués, et des choses étranges pourraient se produire dans votre code.

Permettez-moi de consolider les réponses précédentes.

Il y a en fait deux problèmes ici. On est en train de trancher. Vous initialisez un tableau de virus avec une copie d’un sousvir. Dans de tels cas, le compilateur coupe la partie vir du sous-vir et la copie dans le tableau, de sorte que vous n'obtenez réellement que des objets vir. Dans votre cas particulier, subvir n'a pas d'autres données membres que celles de vir, donc le découpage est quelque peu dégénéré et l'objet vir ressemble beaucoup à un objet subvir. Cependant, vir et subvir sont des classes différentes et l'objet du tableau finit par être un objet vir et non un objet sousvir déguisé en vir. Une des façons dont la différence entre les deux se manifesterait pratiquement, même si les deux avaient les mêmes membres de données, était si vir avait des fonctions virtuelles surchargées par subvir. Dans ce cas, le pointeur vtable dans l'objet du tableau pointerait vers vtable, et non sur subvir. Bien entendu, il serait encore plus explicite que le sous-virage contienne des données supplémentaires non présentes dans vir.

Le deuxième problème est le polymorphisme. Au point d'utilisation (l'appel à move ()), le compilateur pense que vous appelez la méthode move () d'un objet de type vir (puisque le tableau est un tableau de virs). (Le compilateur a bien entendu raison de penser que, en raison du découpage, il peut dégénérer comme il peut l'être dans ce cas.) S'il avait été un objet subvir tel que vous le souhaitiez, vous pourriez obtenir subvir :: move () appelé en faisant move ( ) virtuel en vir.

Pour obtenir le comportement souhaité, vous pouvez utiliser un tableau de pointeurs (mais vous agiriez alors directement sur sv1 et non sur une copie de celui-ci, à moins que vous n'ayez d'abord créé une copie et initialisé le tableau avec un pointeur sur la copie).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top