A quoi sert d'avoir destructor en tant que privé?
Fondamentalement, chaque fois que vous souhaitez qu'une autre classe soit responsable du cycle de vie des objets de votre classe ou que vous avez des raisons d'empêcher la destruction d'un objet, vous pouvez rendre le destructeur privé.
Par exemple, si vous effectuez une sorte de comptage de références, vous pouvez demander à l’objet (ou au gestionnaire qui a été "ami") de compter le nombre de références à lui-même et de le supprimer lorsque le nombre atteint zéro. Un opérateur privé empêcherait quiconque d’en effacer le contenu s’il faisait encore l’objet de références.
Dans un autre cas, que se passe-t-il si un objet ayant un gestionnaire (ou lui-même) peut le détruire ou refuser de le détruire en fonction d'autres conditions du programme, telles qu'une connexion à une base de données ouverte ou un fichier en cours d'écriture? Vous pourriez avoir une méthode "request_delete" dans la classe ou le gestionnaire qui vérifiera cette condition, supprimera ou refusera, et renverra un statut indiquant ce qu'elle a fait. C'est beaucoup plus flexible que d'appeler simplement "supprimer".
Un tel objet ne peut jamais être créé sur la pile. Toujours sur le tas. Et la suppression doit être effectuée via un ami ou un membre. Un produit peut utiliser une seule hiérarchie d'objets et un gestionnaire de mémoire personnalisé - de tels scénarios peuvent utiliser un créateur privé.
#include <iostream>
class a {
~a() {}
friend void delete_a(a* p);
};
void delete_a(a* p) {
delete p;
}
int main()
{
a *p = new a;
delete_a(p);
return 0;
}
Lorsque vous ne souhaitez pas que les utilisateurs accèdent au destructeur, c’est-à-dire que vous voulez que l’objet ne soit détruit que par d’autres moyens.
http://blogs.msdn.com/larryosterman/archive/2005/07/01/434684.aspx donne un exemple, où l'objet est compté en référence et ne doit être détruit que par l'objet lui-même lorsque compte va à zéro.
COM utilise cette stratégie pour supprimer l'instance. COM rend le destructeur privé et fournit une interface pour la suppression de l'instance.
Voici un exemple de ce à quoi ressemblerait une méthode Release.
int MyRefCountedObject::Release()
{
_refCount--;
if ( 0 == _refCount )
{
delete this;
return 0;
}
return _refCount;
}
Les objets COM ATL sont un excellent exemple de ce modèle.
Ajout aux réponses déjà présentes ici; Les constructeurs et destructeurs privés sont très utiles lors de la mise en œuvre de factory où les objets créés doivent être alloués sur le tas. Les objets seraient, en général, créés/supprimés par un membre statique ou un ami. Exemple d'utilisation typique:
class myclass
{
public:
static myclass* create(/* args */) // Factory
{
return new myclass(/* args */);
}
static void destroy(myclass* ptr)
{
delete ptr;
}
private:
myclass(/* args */) { ... } // Private CTOR and DTOR
~myclass() { ... } //
}
int main ()
{
myclass m; // error: ctor and dtor are private
myclass* mp = new myclass (..); // error: private ctor
myclass* mp = myclass::create(..); // OK
delete mp; // error: private dtor
myclass::destroy(mp); // OK
}
La classe ne peut être supprimée que par elle-même. Utile si vous créez un essai d'objet de référence. Ensuite, seule la méthode de publication peut supprimer l'objet, ce qui peut éventuellement vous aider à éviter les erreurs.
Je sais que vous avez posé des questions sur le destructeur privé. Voici comment j'utilise les protégés. L'idée est que vous ne voulez pas supprimer la classe principale via le pointeur vers la classe qui ajoute des fonctionnalités supplémentaires à la classe principale.
Dans l'exemple ci-dessous, je ne souhaite pas que GuiWindow soit supprimé via un pointeur HandlerHolder.
class Handler
{
public:
virtual void onClose() = 0;
protected:
virtual ~Handler();
};
class HandlerHolder
{
public:
void setHandler( Handler* );
Handler* getHandler() const;
protected:
~HandlerHolder(){}
private:
Handler* handler_;
};
class GuiWindow : public HandlerHolder
{
public:
void finish()
{
getHandler()->onClose();
}
virtual ~GuiWindow(){}
};
dirkgently a tort. Voici un exemple d'objet avec c-tor et d-tor privés créés sur une pile (j'utilise une fonction membre statique ici, mais cela peut également être fait avec un ami ou une classe d'amis).
#include <iostream>
class PrivateCD
{
private:
PrivateCD(int i) : _i(i) {};
~PrivateCD(){};
int _i;
public:
static void TryMe(int i)
{
PrivateCD p(i);
cout << "inside PrivateCD::TryMe, p._i = " << p._i << endl;
};
};
int main()
{
PrivateCD::TryMe(8);
};
Ce code produira une sortie: dans PrivateCD :: TryMe, p._i = 8