2010-10-05 12 views
5

Je comprends qu'un des avantages d'avoir des fonctions membres statiques n'est pas d'initialiser une classe pour les utiliser. Il me semble qu'un autre avantage d'eux pourrait ne pas avoir un accès direct aux trucs non statiques de la classe. Par exemple, une pratique courante est que si vous savez qu'une fonction aura des arguments qui ne doivent pas être modifiés, marquez simplement ces constantes. par exemple:Utilisation du mot-clé "statique" pour limiter l'accès aux fonctions membres C++

bool My_Class::do_stuff(const int not_to_be_changed_1, 
         std::vector<int> const * const not_to_be_changed_2) 
{ 
    //I can't change my int var, my vector pointer, or the ints inside it. 
} 

Il est donc correct d'utiliser des fonctions membres statiques pour limiter l'accès. Par exemple, disons que vous avez une fonction

void My_Class::print_error(const unsigned int error_no) { 
    switch (error_no) { 
    case 1: 
     std::cout << "Bad read on..." << std::endl; 
     break; 
    //... 
    default: 
     break; 
    } 
} 

Eh bien ici, on ne va pas à accéder à toutes les variables membres de la classe. Donc, si je l'ai changé la fonction:

static void My_Class::print_error(const unsigned int error_no) { 
    switch (error_no) { 
    case 1: 
     std::cout << "Bad read on..." << std::endl; 
     break; 
    //... 
    default: 
     break; 
    } 
} 

Je voudrais maintenant obtenir une erreur, si j'ai essayé, par inadvertance, d'accéder à l'un de mes var privé, etc. (à moins que je me faire passer une instance de ma classe, qui serait être utile^_ ^!)

Est-ce une technique valide, similaire à la création proactive d'arguments qui ne devraient pas être modifiés constantes? Quels inconvénients peut-il avoir en termes d'efficacité ou d'utilisation? Ma principale raison de demander est que la plupart des tutoriels "statiques" que j'ai lus ne mentionnaient pas l'utilisation de cette façon, donc je me demandais s'il y avait une bonne raison de ne pas le faire, considérant qu'il me semble utile outil.


Edit 1: Une autre justification logique de cette utilisation:

I ont une print_error de fonction, tel que décrit ci-dessus. Je pourrais utiliser un espace de noms:

namespace MY_SPACE { 
    static void print_error(...) { 
     ... 
    } 

    class My_Class { 
     .... 
     void a(void) 
    } 
} 

Mais c'est une douleur, parce que je dois maintenant allonger TOUTES mes déclarations var, à savoir

MY_SPACE::My_Class class_1; 

tous supprimer une fonction de ma classe, que l'essentiel est un membre de ma classe.

Bien sûr, il y a plusieurs niveaux de contrôle d'accès pour les fonctions:

//can't change pointer to list directly 
void My_Class::print_error(std::vector<int> const * error_code_list) {...} 

//can't change pointer to list or list members directly 
void My_Class::print_error(std::vector<int> const * const error_code_list) {...} 

//can't change pointer to list or list members directly, access 
//non-const member vars/functions 
void My_Class::print_error(std::vector<int> const * const error_code_list) const {...} 

//can't change pointer to list or list members directly, access 
//non-static member vars/functions 
static void My_Class::print_error(std::vector<int> const * const error_code_list) {...} 

//can't change pointer to list or list members directly, access 
//member vars/functions that are not BOTH static and const 
static void My_Class::print_error(std::vector<int> const * const error_code_list) const {...} 

Bien sûr, cela est un peu atypique, mais la diminution des degrés sont donc en utilisant les fonctions const et les variables const. J'ai vu beaucoup d'exemples où les gens auraient pu utiliser une fonction const, mais ne l'ont pas fait. Pourtant, certaines personnes pensent que c'est une bonne idée. Je connais beaucoup de programmeurs C++ débutants qui ne comprendraient pas les implications d'une fonction const ou statique. De même, beaucoup comprendrait les deux. Pourquoi certaines personnes s'opposent-elles si catégoriquement à l'utilisation de ce mécanisme de contrôle d'accès si la langue/spécification le prévoit comme tel, comme c'est le cas avec les fonctions const, etc.? Toutes les fonctions membres doivent avoir accès aux autres membres de l'objet

+1

Il semble étrange d'avoir une fonction en tant que membre d'une classe si vous allez lui refuser des droits d'accès aux membres. – JoshD

+2

Une meilleure façon de limiter l'accès consisterait simplement à utiliser une fonction non-membre. Cependant, je ne comprends pas vraiment ce que vous essayez de protéger. –

+1

Dites que vous avez une fonction membre que vous SAVEZ n'a pas besoin d'accéder aux variables/fonctions membres à l'heure actuelle, mais est liée au travail/fonction de la classe. Conceptuellement, son inclusion dans la classe est logique, mais vous voulez vous assurer qu'il n'y a pas d'accès des membres de la classe. Vous pourriez donc en faire une fonction statique, tout comme vous feriez une variable que vous voulez empêcher l'accès à une variable 'const'. Bien sûr, vous pourriez juste délibérément ne pas toucher la variable/membres, et donc ne pas utiliser 'const' /' static', mais beaucoup choisissent de pécher par excès de prudence, au moins dans leur utilisation de 'const'. –

Répondre

1

Les fonctions membres statiques doivent être utilisées lorsqu'elles sont pertinent pour la classe mais ne fonctionne pas sur une instance de la classe.Les exemples incluent une classe de méthodes utilitaires, qui sont toutes statiques car vous n'avez jamais besoin d'une instance réelle de la classe d'utilité elle-même.

Un autre exemple est une classe qui utilise des fonctions auxiliaires statiques, et ces fonctions sont assez utiles pour d'autres fonctions en dehors de la classe.

+0

Donc, basé sur votre réponse sonne comme l'exemple de cas d'utilisation que j'ai initialement affirmé (une fonction d'imprimante d'erreur d'assistance) serait un candidat valide pour 'static' dans votre esprit. –

+0

@Jason: Oui. Bien sûr, je crois que pratiquement toutes les fonctions * doivent être des membres de classe (statiques ou non). Les fonctions nues cassent l'orienté objet (même si je me rends compte que les fonctions de template non-membres sont utiles comme fonctions de "colle"). –

5

Pourquoi essayez-vous de vous protéger de vous-même?

Les éléments statiques sont généralement utilisés avec parcimonie, par exemple en usine. Vous allez créer une situation qui fait que la prochaine personne à travailler avec votre code va "WTF ???"

+1

Eh bien disons que vous avez une fonction membre où vous n'avez absolument pas besoin d'accéder à l'une de vos autres fonctions/variables membres. Ne serait-il pas alors approprié de limiter cet accès en utilisant la statique? Je sais que cela semble étrange, mais en utilisant l'argument que vous pourriez avoir besoin de l'accès et un certain point lorsque le code change, pourrait être utilisé comme un argument contre les constantes en général. –

+4

Vous voulez souvent vous protéger de vous-même. C'est la raison pour laquelle const existe (ou final, ou en lecture seule). Ces modificateurs signalent l'intention et vous empêchent d'utiliser les données de manière non prévue. En outre, pour une fonction comme 'print_error', je préfère la rendre statique et passer dans un flux de sortie, puis utiliser implicitement un flux d'entrée lié à un objet particulier. –

+0

En ce qui concerne la réaction de la personne suivante qui consulte votre code, si vous documentez correctement le code (la raison pour laquelle vous l'avez rendue statique, comme indiqué ci-dessus), vos collègues/collègues doivent comprendre. Tout comme avec const. Quand je vois une const ou une fonction statique, j'essaie de comprendre pourquoi la personne a fait cette distinction.Le meilleur des cas est qu'ils laissent la documentation de pourquoi. –

3

Ne faites pas cela. L'utilisation de static comme mécanisme de contrôle d'accès est une abomination barbare.

L'une des raisons de ne pas le faire est parce qu'il est bizarre. Les programmeurs de maintenance auront du mal à comprendre votre code, car c'est tellement bizarre. Le code maintenable est bon. Tout le monde obtient const méthodes. Personne ne reçoit static-as-const. La meilleure documentation pour votre code est le code lui-même. Le code auto-documenté est un objectif auquel vous devriez aspirer. Pas pour que vous n'ayez pas à écrire des commentaires, mais pour que ils ne devront pas lire eux. Parce que vous savez qu'ils ne vont pas de toute façon. Une autre raison de ne pas le faire est que vous ne savez jamais ce que l'avenir nous réserve. Votre méthode print_error ci-dessus n'a pas besoin d'accéder à l'état de la classe - maintenant. Mais je peux voir comment un jour pourrait avoir besoin de. Supposons que votre classe est un wrapper autour d'un socket UDP. Au milieu de la session, l'autre bout claque la porte. Tu veux savoir pourquoi. Les derniers messages que vous avez envoyés ou reçus peuvent contenir un indice. Ne devriez-vous pas le jeter? Vous avez besoin d'un état pour cela.

Une fausse raison de faire ceci est parce qu'il fournit le contrôle d'accès de membre. Oui, il le fait, mais il existe déjà des mécanismes pour cela. Supposons que vous écrivez une fonction que vous voulez être sûr de ne pas changer l'état de l'objet. Par exemple, print_error ne doit pas modifier l'état de l'objet. Alors faites la méthode const:

class MyClass 
{ 
public: 
    void print_error(const unsigned int error_no) const; 
}; 

...

void MyClass::print_error(const unsigned int error_no) const 
{ 
    // do stuff 
} 

print_error est une méthode const, ce qui signifie effectivement que le pointeur this est const. Vous ne pouvez pas modifier les membres non mutable et vous ne pouvez pas appeler les méthodes non const. N'est-ce pas vraiment ce que tu veux?

+1

+1 pour 'abomination barbare' – JoshD

+1

Mais pourquoi la spécification autorise-t-elle les fonctions membres 'static' alors, si elle n'est pas réservée aux fonctions auxiliaires n'ayant pas besoin de s'appuyer sur d'autres membres de classe ou d'utiliser des variables de classe (mis à part une bibliothèque de fonctions d'aide, peut-être ...)? –

+0

Voir ma description ci-dessus de différents niveaux d'accès dans ma nouvelle section intitulée "Modifier 1". –

1

Il est certainement juste de dire que les fonctions de portée globale, les fonctions membres statiques et les fonctions amis ne sont pas tout à fait orthogonales entre elles. Dans une certaine mesure, c'est en grande partie parce qu'ils sont destinés à avoir une signification sémantique quelque peu différente pour le programmeur, même s'ils produisent une sortie similaire.

En particulier, la seule différence entre une méthode membre statique et une fonction ami est que les espaces de noms sont différents, le membre statique a un espace de noms ::className::methodName et la fonction ami est juste ::friendFunctionName. Ils fonctionnent tous les deux de la même manière. Eh bien, en fait, il y a une autre différence, les méthodes statiques sont accessibles via l'indirection de pointeur, ce qui peut être utile dans le cas des classes polymorphes.

Donc la question est, est-ce que la fonction appartient à "part" de la classe? Si c'est le cas, utilisez une méthode statique. sinon, placez la méthode dans la portée globale et faites-en une amie si elle a besoin d'accéder aux variables membres privées (ou si elle ne le fait pas)