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, A
s'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.