class DLLElement CopieInterface
{
public:
virtual ElementBase* dupliquerZone(ZoneElement* zoneCible);
};
class DLLElement ZoneElement
{
public:
ZoneElement(ElementBase* ptrElement = nullptr);
public:
ElementBase* m_ptrElementCopie;
};
La classe CopieInterface représente l'implémentation la plus élémentaire du système.
Son unique méthode virtuelle permet de gérer la duplication des objets via une zone de copie. Cette abstractino Sert principalement d'interface pour les mécanismes de clonage d'objets.
Examinons maintenant la définition de la classe ZoneElement
Cet élément contient uniquement un pointeur ElementBase nommé m_ptrElementCopie, dont le rôle est de stocker la référence de l'objet à dupliquer.
Voici le constructeur correspondant :
ZoneElement::ZoneElement(ElementBase* ptrElement)
{
m_ptrElementCopie = ptrElement;
}
On observe que ZoneElement ne fait que conserver une référence vers un objet ElementBase. Son utilité réside dans le processus de copie entre sous-classes d'ElementBase.
Prenons l'exemple de l'implémentation dans ElementAction::dupliquerZone(ZoneElement* zoneCible) :
ElementBase* ElementAction::dupliquerZone(ZoneElement* zoneCible)
{
ZoneElement* nouvelleZone = nullptr;
ElementAction* resultat = nullptr;
if (zoneCible && zoneCible->m_ptrElementCopie)
{
resultat = static_cast<ElementAction*>(zoneCible->m_ptrElementCopie);
}
else
{
resultat = new ElementAction();
nouvelleZone = new ZoneElement(resultat);
}
resultat->m_identifiantTag = m_identifiantTag;
delete nouvelleZone;
return resultat;
}
La classe ElementBase hérite de CopieInterface et offre deux fonctionnalités essentielles. Le système de comptage de références permet la gestion manuelle de la mémoire, tandis que le mécanisme de libération automatique gère la mémoire de façon autonome.
Voici la définition complète de la classe ElementBase :
class DLLElement ElementBase : public CopieInterface
{
public:
unsigned int m_idUnique;
int m_referenceLua;
protected:
unsigned int m_compteurReferences;
unsigned int m_compteurAutoLib;
public:
ElementBase(void);
virtual ~ElementBase(void);
void liberer(void);
void retenir(void);
ElementBase* libererAuto(void);
ElementBase* dupliquer(void);
bool estReferenceUnique(void) const;
unsigned int obtenirNombreReferences(void) const;
virtual bool estEqual(const ElementBase* objetCible);
virtual void accepterVisiteur(VisiteurDonnees& visitor);
virtual void mettreAJour(float delta) {}
friend class PoolLiberationAuto;
};
L'implémentation correspondante permet de comprendre le fonctionnement détaillé de chaque méthode :
ElementBase* CopieInterface::dupliquerZone(ZoneElement* zoneCible)
{
(void)zoneCible;
CCAssert(0, "non implementé");
return nullptr;
}
ElementBase::ElementBase(void)
: m_referenceLua(0)
, m_compteurReferences(1)
, m_compteurAutoLib(0)
{
static unsigned int compteurObjets = 0;
m_idUnique = ++compteurObjets;
}
ElementBase::~ElementBase(void)
{
if (m_compteurAutoLib > 0)
{
GestionnairePools::recupererInstance()->retirerObjet(this);
}
if (m_referenceLua)
{
GestionnaireMoteursScripts::recupererInstance()
->obtenirMoteurScript()
->supprimerObjetScript(this);
}
else
{
ProtocoleMoteurScript* moteur = GestionnaireMoteursScripts::recupererInstance()->obtenirMoteurScript();
if (moteur != nullptr && moteur->obtenirTypeScript() == TypeScriptJavascript)
{
moteur->supprimerObjetScript(this);
}
}
}
ElementBase* ElementBase::dupliquer()
{
return dupliquerZone(nullptr);
}
void ElementBase::liberer(void)
{
CCAssert(m_compteurReferences > 0, "le compteur de références doit être supérieur à zéro");
--m_compteurReferences;
if (m_compteurReferences == 0)
{
delete this;
}
}
void ElementBase::retenir(void)
{
CCAssert(m_compteurReferences > 0, "le compteur de références doit être supérieur à zéro");
++m_compteurReferences;
}
ElementBase* ElementBase::libererAuto(void)
{
GestionnairePools::recupererInstance()->ajouterObjet(this);
return this;
}
bool ElementBase::estReferenceUnique(void) const
{
return m_compteurReferences == 1;
}
unsigned int ElementBase::obtenirNombreReferences(void) const
{
return m_compteurReferences;
}
bool ElementBase::estEqual(const ElementBase* objetCible)
{
return this == objetCible;
}
void ElementBase::accepterVisiteur(VisiteurDonnees& visitor)
{
visitor.visiterObjet(this);
}
Trois macros supplémentaires méritent d'être présentées : NS_CC_BEGIN, NS_CC_END et UTILISER_NS_CC.
Leurs définitions sont les suivantes :
#define NS_CC_BEGIN namespace cocos2d {
#define NS_CC_END }
#define UTILISER_NS_CC using namespace cocos2d
Ces deux premières macros permettent de déclarer l'espace de noms cocos2d de manière synthétique. La syntaxe équivalente serait :
namespace cocos2d {
// votre code ici
}
La troisième macro constitue simplement un alias pour l'instruction using namespace cocos2d. Son utilité reste discutable, cetrains préférant l'écriture directe pour plus de clarté.