42 votes

La simplification de const Surcharge?

J'ai été l'enseignement d'une programmation en C++ de la classe depuis de nombreuses années maintenant et l'un des plus délicats de choses à expliquer à des élèves est const surcharge. J'ai souvent l'exemple d'un vecteur comme la classe et de ses operator[] fonction de:

template <typename T> class Vector {
public:
    T& operator[] (size_t index);
    const T& operator[] (size_t index) const;
};

J'ai peu de mal à expliquer pourquoi il est que les deux versions de l' operator[] fonction sont nécessaires, mais en essayant d'expliquer comment unifier les deux implémentations ensemble, je me retrouve souvent à perdre beaucoup de temps avec les arcanes de la langue. Le problème est que le seul moyen fiable et que je sais comment mettre en œuvre l'une de ces fonctions dans les termes de l'autre, est à l' const_cast/static_cast truc:

template <typename T> const T& Vector<T>::operator[] (size_t index) const {
     /* ... your implementation here ... */
}
template <typename T> T& Vector<T>::operator[] (size_t index) {
    return const_cast<T&>(static_cast<const Vector&>(*this)[index]);
}

Le problème de cette configuration est qu'elle est extrêmement difficile à expliquer et pas du tout intuitivement évident. Lorsque vous l'expliquer comme le "cast de const, puis d'appeler le const version, puis la bande constness" c'est un peu plus facile à comprendre, mais la syntaxe est effrayant. Expliquant ce qu' const_cast est, pourquoi il est approprié ici, et pourquoi il est presque universellement inapproprié ailleurs généralement me prend cinq à dix minutes de temps d'enseignement, et de donner un sens à cette expression nécessite souvent plus d'efforts que la différence entre const T* et T* const. J'ai l'impression que les élèves ont besoin de savoir à propos de const-surcharge et comment le faire sans inutilement dupliquer le code dans les deux fonctions, mais cette astuce semble un peu excessif dans un cours d'introduction à la programmation en C++ cours.

Ma question est-ce - est-il un moyen plus simple à mettre en oeuvre const-fonctions surchargées en termes de l'un à l'autre? Ou est-il un moyen plus simple d'expliquer ce truc pour les étudiants?

12voto

J'ai l'habitude de considérer cela comme une restriction de langue, et de conseiller les gens qui, à moins qu'ils vraiment savoir ce qu'ils font -- ils devraient tout simplement ré-écrire. Dans la grande majorité des cas, ces fonctions sont simples d'une ligne getters, donc il n'y a pas de douleur.

En votre qualité de l'enseignement du C++, je me sentirais encore plus fortement sur cette approche.

8voto

Sean Points 15363

Comment sur simplement de le décomposer en étapes plus petites?

const Vector<T>& const_this = *this;
const T& const_elem = const_this[index];
T& mutable_elem = const_cast<T&>(const_elem);
return mutable_elem;

Vous pouvez même éliminer l' static_cast de cette façon, bien que vous pourriez la laisser dans si vous pensez qu'il serait plus clair.

7voto

7vies Points 1373

C'est un truc de dingue, mais cela peut être fait à l'aide d'un modèle statique aide comme ceci

// template parameters can be const or non-const
template<class Ret, class C>
static Ret& get(C* p, size_t index) { /* common code here like p->array[index] */ }

Ensuite, vous pouvez écrire

const T& operator[](size_t index) const { return get<const T>(this, index); }
T& operator[](size_t index) { return get<T>(this, index); }

Cette astuce évite de jette (!) et double la mise en œuvre, mais, encore une fois, il semble étrange pour moi :)

Et une petite remarque à propos de votre extrait de code, ne const_cast être suffisamment en lieu et place de l' static_cast, ou ai-je raté quelque chose?

6voto

Loki Astari Points 116129

Vous pouvez supprimer un lancer en utilisant une méthode privée:
Il ajoute une méthode, mais le fait de coulée moins complexe:

template <typename T>
class Vector
{
  public:
    T const& operator[](size_t i) const { return getValue(i);}
    T&       operator[](size_t i)       { return const_cast<T&>(getValue(i));}

  private:
    T const& getValue(size_t i) const   { return /* STUFF */;}
};

3voto

Crazy Eddie Points 23778

À mon avis, c'est juste ridicule. Vous êtes forçant à mettre en œuvre en termes de l'autre, pour le simple plaisir de le faire, pas parce que le code résultant est plus facile à maintenir ou à comprendre. La raison de vos élèves sont confus est probablement parce qu'ils DEVRAIENT être.

Pas chaque principe doit être pris à l'exclusivité de l'extrême. Parfois redondante est tout simplement mieux.

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