7
votes

Copier et échanger des idioms avec une classe virtuelle pure

J'essaie de mettre en œuvre une classe virtuelle avec une méthode virtuelle pure et «copier et échanvoir», mais j'ai rencontré des problèmes. Le code ne compile pas car je crée une instance dans l'opérateur d'affectation de la classe A contenant une méthode virtuelle pure.

Y a-t-il une façon d'utiliser la méthode virtuelle pure et de copier et échanger des idioms? P>

In member function ‘A& A::operator=(const A&)’:|
error: cannot declare variable ‘tmp’ to be of abstract type ‘A’|
because the following virtual functions are pure within ‘A’:|
virtual void A::print(std::ostream&)|


5 commentaires

Vous ne pouvez pas avoir un TMP (rhs); . A est une classe abstraite.


@MOHITJAIN Je pense qu'il est bien conscient de cela. C'est pourquoi il demande comment travailler autour de cela.


Peut-être Cette réponse est également utile


L'idiome Copy & Swap ne doit pas être combiné avec des fonctions virtuelles / des hiérarchies de classe. Cela conduit à la tranchée (et à l'UB) et à la mise en œuvre lente (car votre objet de copie temporaire crée une table de fonction virtuelle complète). Au lieu de cela, si vous souhaitez duplication / affectation avec une classe de base virtuelle, base de votre implémentation sur un Fonction clone avec type de retour Covariant .


BTW: Les plus avantages de la copie et de l'échange sont venus si vous faites un & opérateur = (un rhs) {échangez (* this, rhs); retour * ceci; }


4 Réponses :


4
votes

Lorsque votre compilateur vous informe, vous ne pouvez pas créer une variable de type abstrait. Il n'y a aucun moyen de danser autour de cela.

Ceci vous laisse trois options principales:

Arrêtez d'utiliser des fonctions virtuelles pure

Premièrement, vous pouvez simplement vous débarrasser des méthodes virtuelles pures et fournir un peu de talon dans chacun d'eux qui appelle std :: terminer , qui perfectionnerait évidemment la détection de temps de compilation de savoir si toutes les méthodes virtuelles (anciennes) pure sont remplacées dans toutes les classes dérivées.

Cela provoquera Tranchement , car il ne copiera que la classe de base et tout ce qui indique que la classe dérivée est perdue.

Utilisez une classe de stub avec des fonctions virtuelles pure

similaires à cela, vous pouvez créer une classe dérivée qui implémente toutes les méthodes virtuelles avec des talons simples (éventuellement appeler std :: ter minate ) et est utilisé uniquement comme une "version instantanée de la classe de base".

La partie la plus importante à mettre en œuvre pour cette classe serait un constructeur qui prend un Constons référence à la classe de base, de sorte que vous pouvez simplement l'utiliser au lieu de copier la classe de base. Cet exemple ajoute également un constructeur de déplacement, car je suis un fétichiste de la performance.

Ceci provoque la même chose Tranchement problème comme première option. Cela peut être votre résultat souhaité, en fonction de ce que vous faites. xxx

Remarque: il s'agit vraiment d'une variable de type A , bien que j'ai dit Cela ne pouvait pas être fait. La seule chose que vous devez être consciente est que la variable de type a vit dans une variable de type instantiediatablea !

Utilisez une copie usine

Enfin, vous pouvez ajouter un Copier virtuel A * () = 0; à la classe de base. Votre classe dérivée B devra ensuite l'implémenter comme a * copie () remplacer {retour nouveau b (* this); } . La mémoire dynamique de la raison est nécessaire, car vos types dérivés peuvent nécessiter une mémoire plus arbitraire que votre classe de base.


0 commentaires

-1
votes

Le compilateur a raison. La classe A code> est une classe abstraite, vous ne pouvez donc pas créer d'instances de celui-ci dans l'opérateur = code>.

in b, vous venez de déclarer le imprimer code> fonction, mais vous ne l'avez pas impliqué. Signification, vous obtiendrez des erreurs de liaison. P>

En la mettant en œuvre, il compile une amende (si nous ignorons diverses avertissements): P>

void B::print(ostream & os )
{
  os << m_att;
}
  • B hérite de privé d'A, est-ce ce que vous vouliez? Li>
  • L'ordre d'initialisation dans le constructeur de copie d'A est faux li>
  • Vous avez initialisé M_TYPE dans le corps du constructeur d'un constructeur et non dans la liste d'initialisation li> ul> p>


0 commentaires

1
votes

Vous êtes juste confronté au fait que l'héritage fonctionne maladroitement avec la sémantique de la copie.

Par exemple, imaginez que vous avez trouvé un astuce pour passer la phase de compilation, ce qui signifierait (l'exemple suivant utilise l'affectation, mais le problème est identique à une copie): P>

// class A
// a class B : public A
// another class C : public A inheriting publicly from A
// another class D : public B inheriting publicly from B
B b1;
C c1;
D d1;

// Which semantic for following valid construction when copy/assignment is defined in A ?
b1 = c1;
b1 = d1;

A &ra = b1;
B b2;

// Which semantic for following valid construction when copy/assignment is defined in A ?
ra = b2;
ra = c1;
ra = d1;


3 commentaires

Cela ne répond pas vraiment à la question de l'OP.


@ Lethal-guitare: Eh bien, je pense que je le fais. C'est parce que la question, à mon avis, ne peut pas être répondue correctement sans créer un gros problème de conception. Il répond donc à la question en disant que le numéro initial est dans le souhait de mettre en œuvre une copie et un échange pour un type d'entité.


Je vois, bien, vous pourriez envisager de la modifier dans votre réponse pour le rendre plus clair.



0
votes

CRTP est un choix: xxx

classe d'utilisateurs: xxx

acclamations, Fm.


0 commentaires