2010-02-14 4 views
3

J'ai 3 classes. Dans sa forme la plus simple, il ressemble,Travailler avec des fonctions constantes et non constantes - C++

class tree 
{ 
public: 
    tree_node* find_node(const std::string& text) { 
     return factory.find(text); 
    } 
private: 
    tree_node_factory factory; 
} 

class tree_node 
{ 
public: 
    tree_node(const std::string& text) : text_(text) {} 

    const std::string& text() const { 
     return text_; 
    } 

    void set_parent(const tree_node* new_parent); 

private: 
    std::string text_; 
} 

class tree_node_factory 
{ 
public: 
    tree_node* find(const std::string& text); 
private: 
    std::vector<tree_node*> allocated_nodes; 
} 

Je ne veux pas permettre aux utilisateurs de tree de modifier les tree_node renvoyées par les méthodes comme find_node. Alors je l'ai changé, find_node et tree_node_factory::find à,

const tree_node* find_node(const std::string& text) const { 
    return factory.find(text); 
} 

const tree_node* find(const std::string& text) const; 

Le problème est tree interne devrait être en mesure de modifier les nœuds et travailler sur des méthodes comme set_parent. Mais depuis l'usine ne retourne que const nœuds, j'ai fini avec ajouter une autre surcharge (version non const) de find dans l'usine. Je me demande si c'est la bonne façon de gérer ce genre de problèmes? Je vois que le code est dupliqué dans les versions const et non-const.

Toutes les pensées ..?

+1

Ceci est normal; Regardez la plupart des classes STL et vous verrez qu'elles fournissent à la fois des versions const et non-const. Je pense que c'est Sutter qui parle d'une façon d'utiliser (bien formé) 'const_cast' et' static_cast' ensemble pour supprimer la duplication de code (en appelant l'autre version); Je soupçonne quelqu'un de l'afficher. Mais oui, c'est normal. – GManNickG

+0

C'est cool. Merci GMan. –

+0

en double - http://stackoverflow.com/questions/123758/how-do-i-remove-code-duplication-between-similar-const-and-non-const-member-funct – Manuel

Répondre

3

Malheureusement C++ n'a pas d'outils (en plus des macros) pour éliminer la duplication de code source dans la fonction qui surcharge l'air en grande partie identiques mais qui diffèrent par constness. Vous pouvez toutefois implémenter l'une des fonctions en utilisant l'autre et const_cast.

7

Rubrique 3 dans le livre de Scott Meyers C++ effectif illustre une méthode pour supprimer cette duplication de code. Fondamentalement, dans votre fonction non-const, vous allez ajouter const à this, appelez la version const, puis jetez la const loin. C'est sûr Bien que l'écriture dans une const-variable mène à un comportement indéfini, parce que this était à l'origine non-const, c'est correct.

Exemple:

const std::string& operator[](size_t index) const 
{ 
    // some other code 

    // since `this` isn't really const, this is modifiable 
    return mData[index]; 
} 

std::string& operator[](size_t index) 
{ 
    return const_cast<std::string&> // (3) take const off result 
      (static_cast<const my_type&> // (1) add const 
      (*this)[index]); // (2) use const version 

} 

Normalement, il serait tout sur une seule ligne. Vous pouvez également faire un utilitaire pour cela.

Remarque une mise en garde: si la version const retourne un objet const « réel », cette méthode se traduit clairement dans le comportement non défini. La constance de la valeur de retour doit être reflétée par la constance de l'objet référencé par this. Ce code est cassé:

const std::string& operator[](size_t index) const 
{ 
    static const std::string constString = "Don't modify me."; 

    if (index == 0) 
    { 
     // even though `this` isn't really const, this is NOT modifiable 
     return constString; 
    } 

    return mData[index - 1]; 
} 

std::string& operator[](size_t index) 
{ 
    return const_cast<std::string&> // (3) !!! take const off result !!! 
      (static_cast<const my_type&> // (1) 
      (*this)[index]); // (2) 

} 

Dans la pratique, nous évitons donc état global ce qui est rarement un problème. C'est trivial de vérifier, de toute façon.

+0

+1 pour l'exemple de code. – Tronic