6
votes

C ++ Opérateurs de conversion implicites

J'essaie de trouver une belle solution de héritage en C ++.

J'ai une classe rectangle et une classe carrée. La classe Square ne peut pas hériter publiquement du rectangle, car elle ne peut pas remplir complètement les exigences du rectangle. Par exemple, un rectangle peut avoir sa largeur et une hauteur de la hauteur de chaque ensemble séparément, et cela est bien sûr impossible avec un carré.

Donc, mon dilemme. Square partagera évidemment beaucoup de code avec rectangle; Ils sont assez similaires.

pour examllpe, si j'ai une fonction comme: xxx

Il devrait également fonctionner pour un carré. En fait, j'ai une tonne de telles fonctions.

Donc, dans la fabrication de ma classe carrée, j'ai pensé que j'utiliserais héritage privé avec un opérateur de conversion rectangulaire accessible au public. Donc, ma classe carrée ressemble à: xxx

Cependant, lorsque j'essaie de passer un carré à la fonction IspointInrectangle, mon compilateur se plaint de ce "rectangle est une base inaccessible" en ce sens que le contexte. Je m'attends à ce qu'il remarque l'opérateur de rectangle et à utiliser cela à la place.

est ce que j'essaie de faire même possible?

Si cela ne peut pas fonctionner, je ne vais probablement pas marcher Refacteur Partie du rectangle dans MutaBerectangle classe.

Merci.


0 commentaires

3 Réponses :


7
votes

Vous pouvez créer une classe immutablérectangle , sans aucun mutateur et avec uniquement des méthodes const , à partir desquelles vous pouvez calculer correctement les deux rectangle , et , séparément, immutablesQuare et, à partir de celui-ci, carré . Notez que, thannie d'une mutabilité, le est-a-a-relation fait est-un carré immuable est-un rectangle immuable: une mutabilité est le seul problème grave, donc en l'emportant Vous pouvez obtenir une nouvelle réutilisation de code substantielle (pour tous les const utilise - ceux qui n'utilisent pas, ni besoin, mutabilité).

L'introduction mutabilité le long de l'héritage est correcte, tant qu'aucun invariance de classe de la base (immuable) réellement net sur la caractéristique de l'immutabilité; Et bien sûr, un objet immuable peut être correctement construit à partir d'un pointeur const ou de référence à la version mutable (probablement dans une fonction d'ami en ligne distincte pour éviter de donner une dépendance de la classe de base sur la classe dérivée ;-) pour une utilisation raisonnablement pratique.

EDIT : Un commentaire exprime de manière compréhensible les scrupules car "une mutabe n'est pas immuable": pour raisonner à ce sujet, vous devez comprendre ce que "est-a" signifie ... et il fait pas signifie le Korzybski -Dentied " est de l'identité ": cela signifie le LSP . Passez à travers le rigueur des contraintes que cela signifie: covariance, contravariace, faibles conditions préalables, postconditions plus fortes, etc., comme ils s'appliquent aux méthodes const de la base ( immuables) et des classes dérivées (mutables). Vous verrez que les invariants de classe sont le seul problème, comme je l'ai mentionné dans le paragraphe précédent, évitez donc d'affirmer une immuabilité comme invariant de classe et vous êtes dans le trèfle; -).

Peut-être que cela aiderait à nommer la classe de base notnyentailymutablerectangle car il ne affirme immutabilité comme invariant de classe; que la nommée très précise pourrait être philosophiquement rassurante, mais peut-être une bagatelle non pratique dans le codage quotidien.


8 commentaires

Cela peut être "ok" - j'ai certainement donné un +1 - mais c'est un peu déconcertant d'avoir le principe "Isa" brisé comme ça. Une mutable la plus définitive isnota immutable.


@Steve, mais le point est, comment le principe de substitution de Liskov serait-il cassé si vous avez passé dans un carré où l'arg est const immutablérectangle & x ? Ce ne serait pas - la callee n'appelle que des méthodes (const) sur x , et tout fonctionne. que est ce que ISA signifie dans OOP - pas "le cas d'identité". Je vais éditer la réponse pour annoncer cette clarification ... TX pour exprimer vos doutes!


Je ne suis pas sûr de besoin d'une édition - vous avez déjà mentionné des invariants. Mon point est, je suppose que cette intuition et que le principe théorique ne correspond pas toujours exactement. Une bonne approche peut encore parfois être un peu déconcertante. Dans un autre contexte, l'héritage comme s'étendant plutôt que d'Isa aurait été beaucoup moins de jarring - mais il y a juste quelque chose à propos de formes, probablement à cause de toutes ces exemples de salle de classe et de manuels.


OTOH - Cela pourrait être un problème de nom. MutaBerectangle ISA Rectangle, et il n'y a aucune raison pour laquelle le rectangle ne peut pas avoir toutes les fonctionnalités immuables construites. Pour moi, c'est moins de jarre.


@Steve, vous pouvez avoir raison de la nommer - peut-être que les noms de base des classes représentant des entités mathématiques telles que des formes devraient impliquer immutabilité au moins dans le sens de "pas nécessairement mutable" (plus mathématiquement et philosophiquement Traitable) et un préfixe mutable indiquent spécifiquement les classes mutables.


"Une bagatelle non pratique" une bagatelle pas nécessairement - pratique? L'ambiguïté est juste entre "immuable", ce qui signifie "Cet objet ne permet pas le changement" et "immuable", ce qui signifie "cette interface à l'objet ne permet pas le changement". Si un joueur de certains sports est "imparable", cela ne signifie pas qu'elle ne s'arrête jamais, mais en contraste "données immuables" signifie généralement que cela ne peut changer par aucun moyen. J'aime la solution de rectangle étant le nom de l'interface de base, avec mutablerectangle une spécialisation, et peut-être immutablérectangle une autre spécialisation, avec une fonction pour "geler" un rectangle.


@Steve Jessop - Oui, mais le nom implique une immuabilité comme invariant de classe. Le problème est que l'assurance-mutabilité est un trait viral - une seule opération de mutation et l'objet est mutable, quel que soit le nombre d'opérations non mutatings, il peut y avoir. Je suis revenu pour dire que et fondamentalement "Qu'en est-il de rectangle Isa Rectanglebasebasebase?", Mais "rectangle a construisible" est bon. La clarification de l'immuabilité n'est pas une invariative de classe, mais la charge utile non mutation est - cela fait une différence. OTOH, l'anglais n'a aucune obligation de fournir à La Mot Juste.


@Steve Jessop: Les objets immuables ont un contrat avec tout utilisateur prometteur qu'ils ne changeront pas. Deux objets immuables comparateurs égaux comparent toujours égaux et peuvent être utilisés de manière interchangeable. Je suggérerais d'avoir une classe de base générique avec des propriétés pour lire des attributs de forme; Il peut reprocher des descendants mutables et immuables; Des choses qui ne changent pas de forme elles-mêmes mais ne se soucient pas si quelqu'un d'autre pourrait le faire peut accepter des objets de la classe générique. Les classes immuables risquent de bien accepter les objets de classe générique dans leurs constructeurs de copies.



0
votes

Je crois, bien que je ne suis pas certain, que vous devez utiliser une extinction explicite pour invoquer cet opérateur de conversion dans ce contexte. La base immutablérectangle est une solution commune et efficace. De même, vous pouvez utiliser une solution plus abstraite telle que: xxx


0 commentaires

4
votes

Eh bien, je suis surpris. Il semble hériter de manière privée d'une classe A empêche d'utiliser l'opérateur A à l'extérieur de la classe.

Vous pouvez résoudre votre problème en faisant un rectangle de membre pour le carré et en l'utilisant pour la distribution: P>

class Square {
    Rectangle r;
    public:
        operator const Rectangle&() const {
            return r;
        }
};


1 commentaires

Cela a bien fonctionné pour moi (il suffit d'ajouter "R." devant quelques choses). Bien que je ne comprends pas pourquoi l'héritage privé affecte l'interface publique d'une classe. Je pensais que privé signifiait privé.