138 votes

Solution élégante pour dupliquer, constants et non-constants, getters?

Ne vous détestez pas quand vous avez

 class Foobar {
public:
    Something& getSomething(int index) {
        // big, non-trivial chunk of code...
        return something;
    }

    const Something& getSomething(int index) const {
        // big, non-trivial chunk of code...
        return something;
    }
}
 

Nous ne pouvons pas implémenter l'une ou l'autre de ces méthodes avec l'autre, car vous ne pouvez pas appeler la version non const partir de la version const (erreur du compilateur). Une distribution sera nécessaire pour appeler la version const partir de la version non const .

Existe-t-il une solution élégante à ce problème, sinon quelle est la solution la plus proche?

136voto

CAdaker Points 3947

Je me souviens d'un des livres de Effective C ++ que la solution consiste à implémenter la version non-const en écartant le const de l'autre fonction.

Ce n'est pas particulièrement joli, mais c'est sûr. Etant donné que la fonction membre qui l'appelle est non-const, l'objet lui-même est non-const, et il est autorisé de le supprimer.

 class Foo
{
public:
    const int& get() const
    {
        //non-trivial work
        return foo;
    }

    int& get()
    {
        return const_cast<int&>(static_cast<const Foo*>(this)->get());
    }
};
 

30voto

Steve Jessop Points 166970

Comment à ce sujet:

template<typename IN, typename OUT>
OUT BigChunk(IN self, int index) {
    // big, non-trivial chunk of code...
    return something;
}

struct FooBar {
    Something &getSomething(int index) {
        return BigChunk<FooBar*, Something&>(this,index);
    }

    const Something &getSomething(int index) const {
        return BigChunk<const FooBar*, const Something&>(this,index);
    }
};

Évidemment, vous aurez toujours de l'objet de la duplication de code, mais pas de source de duplication de code. Contrairement à la const_cast approche, le compilateur vérifiera votre const-correctness pour les deux versions de la méthode.

Vous avez probablement besoin de déclarer les deux instanciations de BigChunk comme des amis de la classe. C'est une bonne utilisation de l'ami, puisque l'ami des fonctions sont cachés à proximité de la friendee, donc il n'y a pas de risque de contrainte de couplage (ooh-er!). Mais je ne chercherai pas la syntaxe pour le faire dès maintenant. N'hésitez pas à ajouter.

Les Chances sont que BigChunk besoins de respect de soi, auquel cas l'ordre ci-dessus de définition ne va pas fonctionner très bien, et les déclarations seront nécessaires pour faire le tri.

Aussi, afin d'éviter certains numpty trouver BigChunk dans l'en-tête et de décider d'instancier et de l'appeler, même si c'est moralement privé, vous pouvez déplacer l'ensemble du lot dans le fichier cpp pour FooBar. Dans un espace de noms anonymes. Avec une liaison interne. Et un signe en disant: "méfiez-vous du léopard".

8voto

Matthew Flaschen Points 131723

Je jetterais le const au non-const (deuxième option).

4voto

markh44 Points 2080

Essayez d'éliminer les getters par la refactorisation de votre code. Utilisez ami de fonctions ou de classes si seulement un très petit nombre d'autres choses que les besoins de la Chose.

En général, les Getters et les Setters briser l'encapsulation, car les données sont exposées dans le monde. À l'aide de l'ami seulement expose les données à une élite, donc donne une meilleure encapsulation.

Bien sûr, ce n'est pas toujours possible de sorte que vous pourriez être coincé avec les getters. À tout le moins, la plupart ou la totalité de la "non-trivial morceau de code" doit être dans l'une ou plusieurs des fonctions privées, appelée par les deux méthodes.

Prograide.com

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.

Powered by:

X