13.01.2015 Views

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

Pensar en C++ (Volumen 1) - Grupo ARCO

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

✐<br />

✐<br />

✐<br />

“Volum<strong>en</strong>1” — 2012/1/12 — 13:52 — page 175 — #213<br />

✐<br />

5.3. Amigos (fri<strong>en</strong>ds)<br />

}<br />

x.i = 100; // Direct data manipulation<br />

int main() {<br />

X x;<br />

Z z;<br />

z.g(&x);<br />

} ///:~<br />

struct Y ti<strong>en</strong>e un método f() que modifica un objeto de tipo X. Aquí hay<br />

un poco de lío pues <strong>en</strong> <strong>C++</strong> el compilador necesita que usted declare todo antes<br />

de poder hacer refer<strong>en</strong>cia a ello, así struct Y debe estar declarado antes de que<br />

su método Y::f(X*) pueda ser declarado como fri<strong>en</strong>d <strong>en</strong> struct X. Pero para<br />

declarar Y::f(X*), struct X debe estar declarada antes!<br />

Aquí vemos la solución. Dese cu<strong>en</strong>ta de que Y::f(X*) toma como argum<strong>en</strong>to<br />

la dirección de un objeto de tipo X. Esto es fundam<strong>en</strong>tal pues el compilador siempre<br />

sabe cómo pasar una dirección, que es de un tamaño fijo sin importar el tipo, aunque<br />

no t<strong>en</strong>ga información del tamaño real. Si int<strong>en</strong>ta pasar el objeto completo, el compilador<br />

necesita ver la definición completa de X, para saber el tamaño de lo que quiere<br />

pasar y cómo pasarlo, antes de que le permita declarar una función como Y::g(X).<br />

Pasando la dirección de un X, el compilador le permite hacer una id<strong>en</strong>tificación de<br />

tipo incompleta de X antes de declarar Y::f(X*). Esto se consigue con la declaración:<br />

struct X;<br />

Esta declaración simplem<strong>en</strong>te le dice al compilador que hay una estructura con<br />

ese nombre, así que es correcto referirse a ella siempre que sólo se necesite el nombre.<br />

Ahora, <strong>en</strong> struct X, la función Y::f(X*) puede ser declarada como fri<strong>en</strong>d<br />

sin problemas. Si int<strong>en</strong>ta declararla antes de que el compilador haya visto la especificación<br />

completa de Y, habría dado un error. Esto es una restricción para asegurar<br />

consist<strong>en</strong>cia y eliminar errores.<br />

Fíjese <strong>en</strong> las otras dos funciones fri<strong>en</strong>d. La primera declara una función global<br />

ordinaria g() como fri<strong>en</strong>d. Pero g() no ha sido declarada antes como global!.<br />

Se puede usar fri<strong>en</strong>d de esta forma para declarar la función y darle el estado de<br />

fri<strong>en</strong>d simultáneam<strong>en</strong>te. Esto se exti<strong>en</strong>de a estructuras completas:<br />

fri<strong>en</strong>d struct Z;<br />

es una especificación incompleta del tipo Z, y da a toda la estructura el estado de<br />

fri<strong>en</strong>d.<br />

5.3.1. Amigas anidadas<br />

Hacer una estructura anidada no le da acceso a los miembros privados. Para conseguir<br />

esto, se debe: primero, declarar (sin definir) la estructura anidada, después<br />

declararla como fri<strong>en</strong>d, y finalm<strong>en</strong>te definir la estructura. La definición de la estructura<br />

debe estar separada de su declaración como fri<strong>en</strong>d, si no el compilador la<br />

vería como no miembro. Aquí hay un ejemplo:<br />

175<br />

✐<br />

✐<br />

✐<br />

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!