Il s'agissait d'une question d'entretien. Considérez les points suivants :
struct A {};
struct B : A {};
A a;
B b;
a = b;
b = a;
Pourquoi est-ce que b = a;
lancent une erreur, tandis que a = b;
est parfaitement bien ?
Il s'agissait d'une question d'entretien. Considérez les points suivants :
struct A {};
struct B : A {};
A a;
B b;
a = b;
b = a;
Pourquoi est-ce que b = a;
lancent une erreur, tandis que a = b;
est parfaitement bien ?
Étant donné que l'opérateur d'affectation par copie implicitement déclaré de l'option B
cache l'opérateur d'affectation de copie implicitement déclaré de A
.
Donc pour la ligne b = a
seulement le operator=
de B
est un candidat. Mais son paramètre est de type B const&
qui ne peut pas être initialisé par un A
argument (vous auriez besoin d'une baisse). Vous obtenez donc une erreur.
Parce que chaque B est un A, mais pas chaque A est un B.
J'ai modifié les commentaires suivants pour rendre les choses un peu plus claires (j'ai modifié votre exemple) :
struct A {int someInt;};
struct B : A {int anotherInt};
A a;
B b;
/* Compiler thinks: B inherits from A, so I'm going to create
a new A from b, stripping B-specific fields. Then, I assign it to a.
Let's do this!
*/
a = b;
/* Compiler thinks: I'm missing some information here! If I create a new B
from a, what do I put in b.anotherInt?
Let's not do this!
*/
b = a;
Dans votre exemple, il n'y a pas d'attributs someInt
ni anotherInt
donc il podría travail. Mais le compilateur ne le permettra pas de toute façon.
Il est vrai qu'un B
est un A
mais un A
n'est pas un B
mais ce fait n'est directement applicable que lorsque vous travaillez avec des pointeurs ou des références à des fichiers de type A
et B
's. Le problème ici est votre opérateur d'affectation.
struct A {};
struct B : A {};
Est équivalent à
struct A {
A& operator=(const A&);
};
struct B : A {
B& operator=(const B&);
};
Donc quand tu assignes en dessous :
A a;
B b;
a = b;
L'opérateur d'affectation sur a
peut être appelé avec un argument de b
car un B
est un A
donc b
peut être passé à l'opérateur d'affectation comme un A&
. Notez que a
L'opérateur d'assignation de l'UE ne connaît que les données qui se trouvent dans un fichier de type A
et pas les trucs dans un B
Les membres de B qui ne font pas partie de A sont donc perdus - c'est ce qu'on appelle le "découpage en tranches".
Mais quand vous essayez d'assigner :
b = a;
a
est de type A
qui n'est pas un B
donc a
ne peut pas correspondre à la B&
pour b
L'opérateur d'affectation de l'UE.
On pourrait penser que b=a
devrait juste appeler l'héritage A& A::operator=(const A&)
mais ce n'est pas le cas. L'opérateur d'affectation B& B::operator=(const B&)
cache l'opérateur qui serait hérité de A
. Il peut être restauré à nouveau avec un using A::operator=;
déclaration.
J'ai changé les noms de vos structures pour que la raison soit évidente :
struct Animal {};
struct Bear : Animal {};
Animal a;
Bear b;
a = b; // line 1
b = a; // line 2
Il est clair que tout ours est également un animal, mais tout animal ne peut être considéré comme un ours.
Parce que chaque B "est" A, toute instance de B doit aussi être une instance de A : par définition, elle a les mêmes membres dans le même ordre que toute autre instance de A. Copier b dans a fait perdre les membres spécifiques à B, mais remplit complètement les membres de a, ce qui donne une structure qui satisfait aux exigences de A. Copier a dans b, d'un autre côté, peut laisser b incomplet parce que B pourrait avoir plus de membres que A. C'est difficile à voir ici parce que ni A ni B n'ont de membres du tout, mais c'est pourquoi le compilateur autorise une affectation et pas l'autre.
Rappelez-vous que s'il n'y a pas d'opérateurs de copie-affectation explicitement déclarés, il y en aura un implicitement déclaré et défini pour toute classe (et les structs sont des classes en C++).
Pour struct A
il aura la signature suivante :
A& A::operator=(const A&)
Et il effectue simplement une affectation par membre de ses sous-objets.
a = b;
est OK parce que B
correspondra à la const A&
pour A::operator=(const A&)
. Puisque seuls les membres de A
sont "assignés par membre" à la cible, tous les membres de B
qui ne font pas partie de A
se perdre - c'est ce qu'on appelle le "découpage en tranches".
Pour struct B
l'opérateur d'affectation implcit aura la signature suivante :
B& B::operator=(const B&)
b = a;
n'est pas acceptable car A
ne correspondra pas à la const B&
argument.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.