c++ - usar - variable static java
¿Es posible declarar una función de amigo como estática? (3)
Aquí hay un código de ejemplo de C ++ que compila y funciona bien:
class A
{
public:
A() {/* empty */}
private:
friend void IncrementValue(A &);
int value;
};
void IncrementValue(A & a)
{
a.value++;
}
int main(int, char **)
{
A a;
IncrementValue(a);
return 0;
}
Lo que me gustaría hacer, sin embargo, es declarar IncrementValue () como estático, para que no se pueda ver o llamar desde otra unidad de compilación:
static void IncrementValue(A & a)
{
a.value++;
}
Hacer eso, sin embargo, me da un error de compilación:
temp.cpp: In function ‘void IncrementValue(A&)’:
temp.cpp:12: error: ‘void IncrementValue(A&)’ was declared ‘extern’ and later ‘static’
temp.cpp:8: error: previous declaration of ‘void IncrementValue(A&)’
... y cambiar la declaración de amistad para que coincida no ayuda:
friend static void IncrementValue(A &);
... ya que da este error:
temp.cpp:8: error: storage class specifiers invalid in friend function declarations
Mi pregunta es, ¿hay alguna forma en C ++ de tener una función de amigo (que no sea de método) que se declare estática?
Cotización N3691 - §11.3 / 4 [class.friend]
Una función declarada por primera vez en una declaración de amigo tiene un enlace externo (3.5). De lo contrario, la función conserva su enlace anterior (7.1.1).
Por lo tanto, debe declarar la función como static
antes de declararla como friend
. Esto se puede hacer agregando las siguientes declaraciones sobre la definición de A
class A; // forward declaration, required for following declaration
static void IncrementValue(A&); // the friend declaration will retain static linkage
Por supuesto. Lea atentamente la segunda línea del mensaje de error: la función se declaró extern
y luego static
. Así que todo lo que tienes que hacer es declararlo estático antes de la declaración de amigo:
class A;
static void IncrementValue(A&);
class A {
// class definition, including friend declaration
};
static void IncrementValue(A&) {
// code here, of course
}
Si bien la answer los pretorianos es técnicamente correcta, ya que responde a la pregunta que hizo de manera explícita, creo que no es una respuesta útil ya que lo que él propone no es válido y tampoco cumple con su objetivo declarado de desear definir un método que pueda serlo. Llamado en la unidad de traducción de las clases de amigos solamente.
Hay dos problemas con su solución. En primer lugar, cualquier otra unidad de traducción que incluya el encabezado que contiene la definición de clase precedida por la declaración de función estática no podrá compilarse debido al error de que la función de amigo declarada estáticamente no está definida en el módulo de traducción de referencia. Y, en segundo lugar, la TU de referencia puede eliminar ese error de compilación definiendo la función declarada estáticamente en sí misma, y esa definición podrá acceder a todos los datos privados de la clase de la cual la función fue declarada amiga. Esto sugiere que las funciones de amigo siempre deben dejarse con el enlace público que es su valor predeterminado, ya que esto evita que se produzca una posible brecha de encapsulación debido a que varias definiciones de una función de enlace público son un error de compilación.
Creo que @engf estaba en el camino correcto en su comentario sobre su pregunta, necesita una clase de amigo definida en la misma unidad de traducción que la clase a la que desea que pueda acceder. P.ej
// A.h
class A
{
public:
A() : _value(0) {}
private:
int _value;
friend struct A_Accessor;
};
// A.cpp
struct A_Accessor
{
static void IncrementValue(A& a)
{
++a._value;
}
};
TEST(StaticInit, IncrementA)
{
A a;
A_Accessor::IncrementValue(a);
}
Esto definirá IncrementValue de una manera que le permita acceder a los datos privados de A, pero no puede ser referenciado desde fuera del módulo de traducción de A.