dimarts, de maig 26, 2009

C++ Forward declaration

Ahir vaig descobrir aquesta petita joia.
(Warning! el meu primer post de programació en aquest blog, espero que sigui light. Pels que no sigueu programadors, aqui hi ha un video molt gracios :p )

Imagineu-vos que esteu programant en C++ (suposo que en C també funciona) i us trobeu amb el típic cas de inclusió cíclica.
Es a dir, que tens una classe A i una classe B i que cadascuna hi té declarat un objecte de l'altre classe.

Aquests serien els seus headers.

Aquest seria el fitxer A.h:

-----------------------------------------------
#include "B.h"

class A
{
//objecte de la classe B
B aux;

/* mes coses */
};
-----------------------------------------------

I aquest el B.h:

-----------------------------------------------
#include "A.h"

class B
{
//objecte de la classe A
A aux;

/* mes coses */
};
-----------------------------------------------

A simple vista, sembla que això hagi de funcionar i tal i qual, pero si ho intenteu compilar, el compilador us dirà que nanai, que tenim un problema de dependencia cíclica. Una especie d'abraçada mortal.

Cuidadorl! Abraçada mortal!

Aqui és on ve el forward declaration al rescat.
La idea es que si en el header d'una classe hi fas referència a una altra, pero no l'utilitza ni l'hereta, pots declarar per adelantat que existeix aquesta classe sense la necesitat de definir-la.
El compilador s'ho creurà i confiarà en que més endevant ja hi trobarà aquesta definició.

És a dir, que el cas de més a munt es convertiria en:


Fitxer A.h:

-----------------------------------------------
class B; /*hem canviat el include per aquesta declaració per adelantat.*/

class A
{
//objecte de la classe B
B aux;

/* mes coses */
};
-----------------------------------------------


Fitxer B.h:

-----------------------------------------------
class A; /*aqui tres quarts del mateix*/

class B
{
//objecte de la classe A
A aux;

/* mes coses */
};
-----------------------------------------------

Per que això funcioni be, en algun moment s'han de definir aquestes classes, així que tocara afegir els 2 includes.
On els posem? Dons en els fitxers A.cpp i B.cpp.

Fitxer A.cpp:

-----------------------------------------------
#include "B.h"

/* mes coses */
-----------------------------------------------

Fitxer B.cpp:

-----------------------------------------------
#include "A.h"

/* mes coses */
-----------------------------------------------

Un efecte secundari que te fer les coses d'aquesta manera és una, sempre desitjable, reducció del temps de compilació.
Ja que si es modifica i recompila la classe A, com que B.h ja no inclueix A.h, ja no es recompila (de fet el fitxer A.cpp si que ho faria) , per tant, totes les clases que inclouen B.h tampoc s'han de recompilar, pel que estem evitant el tornar a generar de totes les clases que formin part de l'arbre de dependencia que comença en A.
Guay no?

Doncs aqui acaba el sermon d'avui.

Espero que als colegues fibers (molts dels que segueixen el blog) , que els hi agradi C++ (una petita fracció d'aquests) , i que encara no coneguessin la tonteria aquesta (tornem a reduir el public, lol ), els hi hagi servit per algo.