71 votes

Où utiliseriez-vous une fonction ami par rapport à une fonction membre statique?

Nous faisons un non-membre d'une fonction amie d'une classe quand on en a besoin pour accéder à cette catégorie de membres privés. Ce qui donne les mêmes droits d'accès comme une fonction membre statique aurait. Les deux solutions ne vous donner une fonction qui n'est pas associée à une instance de cette classe.

Quand doit-on utiliser une fonction friend? Quand doit-on utiliser une fonction statique? Si les deux sont des options viables pour résoudre un problème, comment pouvons-nous mesurer leur pertinence? Est-il celui qui doit être préféré par défaut?

Par exemple, lors de la mise en œuvre d'une usine qui crée des instances de la classe foo qui n'a qu'un constructeur privé, cette usine de fonction d'un membre statique d' foo (que vous appelez foo::create()) ou devrait-il être un ami de la fonction (que vous appelez create_foo())?

76voto

pm100 Points 8303

11.5 "langage de programmation c ++" par stroustrop

les fonctions de membre ordinaires obtiennent 3 choses

  1. accès aux internes de la classe
  2. sont dans le cadre de la classe
  3. doit être invoqué sur une instance

amis obtiennent seulement # 1

les fonctions statiques obtiennent 1 et 2

47voto

Andy Prowl Points 62121

La question semble répondre à la situation où le programmeur doit introduire une fonction qui n'a pas de travail sur toute instance d'une classe (d'où la possibilité de choisir un static fonction de membre). Donc, je vais limiter cette réponse à la suite de la conception de la situation, où le choix est entre une fonction statique f() et un ami gratuit fonction f():

struct A
{
    static void f();     // Better this...
private:
    friend void f();  // ...or this?
    static int x;
};

int A::x = 0;

void A::f() // Defines static function
{
    cout << x;
}

void f() // Defines friend free function
{
    cout << A::x;
}

int main()
{
    A::f(); // Invokes static function
    f();    // Invokes friend free function
}

Sans rien connaître à l'avance sur la sémantique de l' f() et A (j'y reviendrai plus tard), ce scénario limité a une réponse simple: l' static fonction est préférable. Je vois deux raisons à cela.


ALGORITHMES GÉNÉRIQUES:

La raison principale est qu'un modèle tel que celui-ci peut être écrite:

template<typename T> void g() { T::f(); }

Si l'on avait deux classes ou plus qui ont un static fonction f() sur leur interface, cela nous permettrait de nous écrire une fonction unique qui invoque f() génériquement sur une catégorie.

Il n'existe aucun moyen d'écrire un équivalent de la fonction générique si nous faisons f() libre, non-membre de la fonction. Même s'il est vrai que l'on pourrait mettre f() dans un espace de noms, de sorte que l' N::f() syntaxe peut être utilisée pour imiter l' A::f() de la syntaxe, il serait toujours impossible d'écrire une fonction de modèle comme g<>() - dessus, parce que les espaces de noms ne sont pas valides arguments de modèle.

REDONDANT DÉCLARATIONS:

La deuxième raison est que si nous devions mettre la fonction libre f() dans un espace de noms, nous ne serions pas autorisés à inline sa définition directement dans la définition de classe sans introduire toute autre déclaration pour f():

struct A
{
    static void f() { cout << x; } // OK
private:
    friend void N::f() { cout << x; } // ERROR 
    static int x;
};

Afin de résoudre ce problème ci-dessus, nous précéder la définition de la classe A avec la déclaration suivante:

namespace N
{
    void f(); // Declaration of f() inside namespace N
}

struct A
{
    ...
private:
    friend void N::f() { cout << x; } // OK
    ...
};

Ceci, cependant, les défaites de notre intention d' f() déclarées et définies dans un seul endroit.

En outre, si nous avons voulu déclarer et définir f() séparément tout en gardant f() dans un espace de noms, nous aurions encore à introduire une déclaration pour f() avant la définition de classe pour A: ne pas le faire entraînerait le compilateur pour se plaindre du fait qu' f() ont dû être déclarée à l'intérieur de l'espace de noms N avant le nom de l' N::f pourrait être utilisé légalement.

Ainsi, on dispose désormais d' f() mentionné dans trois endroits distincts plutôt que seulement deux (déclaration et la définition):

  • La déclaration à l'intérieur de l'espace de noms N avant A's de la définition;
  • L' friend déclaration à l'intérieur d' A's de la définition;
  • La définition de l' f() à l'intérieur de l'espace de noms N.

La raison pour laquelle la déclaration et la définition de l' f() à l'intérieur d' N ne peut pas être rejoint (en général) c'est qu' f() est censé accéder à l'intérieur de l' A et, par conséquent, As'définition doit être considéré lors de f() est défini. Pourtant, comme dit précédemment, f()s'déclaration à l'intérieur d' N doit être vu avant la correspondante friend déclaration à l'intérieur de l' A est faite. Effectivement cela nous oblige à diviser la déclaration et la définition de l' f().


SÉMANTIQUE CONSIDÉRATIONS:

Si ces deux points sont universellement valables, il y a des raisons pour lesquelles on peut se contenter de déclarer f() comme static plus de faire un friend de A ou vice-versa, qui sont déterminés par l'univers de discours.

Pour clarifier, il est important de souligner le fait qu'une fonction membre d'une classe, qu'elle est - static ou de non-static, est logiquement partie de cette classe. Il contribue à sa définition et donc fournit un cadre conceptuel caractérisation de celui-ci.

D'autre part, une friend de la fonction, en dépit de l'accès à l'intérieur de membres de la classe il est ami de, est toujours un algorithme qui est logiquement externe à la définition de la classe.

Une fonction peut être friend de plus d'une classe, mais il peut être membre d'un seul.

Ainsi, dans un domaine d'application, le concepteur peut vouloir tenir compte de la sémantique à la fois la fonction et la classe au moment de décider de faire un friend ou un membre de celle-ci (cela s'applique non seulement à l' static fonctions, mais à la non-static fonctions, là où d'autres contraintes de la langue peut intervenir).

La fonction logiquement contribuer à caractériser une classe et/ou de son comportement, ou est-ce plutôt un externe de l'algorithme? Cette question ne peut être répondu sans connaissance particulière du domaine d'application.


GOÛT:

Je crois que tout argument autre les simplement les tiges purement d'une question de goût: à la fois le libre - friend et de la static membre approche, en fait, permettent d'énoncer clairement ce que l'interface d'une classe est en un seul endroit (la classe de définition), de sorte que la conception-sage ils sont équivalents (modulo les observations ci-dessus, bien sûr).

Les différences sont stylistique: si nous voulons écrire l' static mot-clé ou l' friend mot-clé lors de la déclaration d'une fonction, et si nous voulons écrire l' A:: de portée de classe qualifier lors de la définition de la classe plutôt que de l' N:: de l'espace de noms de la portée de qualification. Donc, je ne ferai pas de commentaire sur cette.

13voto

Alok Save Points 115848

La différence exprime clairement l'intention de la relation entre la classe et la fonction.

Vous utilisez friend lorsque vous souhaitez indiquer intentionnellement un couplage fort et une relation spéciale entre deux classes non liées ou entre une classe et une fonction.

Vous utilisez la fonction membre static lorsque la fonction fait logiquement partie de la classe à laquelle elle appartient.

6voto

thebretness Points 405

Ami des fonctions (et des classes) peut accéder aux membres privés et protégés de votre classe. Il y a rarement une bonne affaire pour l'aide d'un ami de classe ou de fonction. Les éviter en général.

Les fonctions statiques ne peuvent accéder à des données statiques (qui est, de classe, de l'étendue des données). Ils peuvent être appelés sans la création d'une instance de votre classe. Les fonctions statiques sont grands pour les circonstances que vous voulez que toutes les instances de votre classe à se comporter de la même manière. Vous pouvez utiliser:

comme les fonctions de rappel pour manipuler la classe étendue de membres pour récupérer des données constantes que vous ne voulez pas de les énumérer dans votre fichier d'en-tête

4voto

sklitzz Points 524

Les fonctions statiques sont utilisés lorsque vous voulez une fonction qui est la même pour toutes les instances d'une classe. Ces fonctions n'ont pas accès à pointeur "this" et ne peut donc pas accéder à tout non-statiques, les champs. Ils sont souvent utilisés lorsque vous souhaitez une fonction qui peut être utilisée sans l'instanciation de la classe.

Ami de fonctions sont des fonctions qui ne sont pas dans la classe et que vous souhaitez leur donner accès aux membres privés de la classe.

Et ce(statique vs ami) n'est pas une question de l'aide de l'un vs l'autre, car ils ne sont pas opposés.

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