Risposte:
Fondamentalmente, ogni volta che vuoi che un'altra classe sia responsabile del ciclo di vita degli oggetti della tua classe, o hai motivo di impedire la distruzione di un oggetto, puoi rendere privato il distruttore.
Ad esempio, se stai facendo una sorta di cosa di conteggio dei riferimenti, puoi avere l'oggetto (o il manager che è stato "amico" ed) responsabile del conteggio del numero di riferimenti a se stesso ed eliminarlo quando il numero raggiunge lo zero. Un agente privato impedirebbe a chiunque altro di eliminarlo quando vi erano ancora riferimenti ad esso.
Per un'altra istanza, cosa succede se si dispone di un oggetto con un gestore (o se stesso) che potrebbe distruggerlo o rifiutare di distruggerlo a seconda di altre condizioni nel programma, come una connessione al database aperta o un file in fase di scrittura. Potresti avere un metodo "request_delete" nella classe o nel gestore che controllerà quella condizione e cancellerà o rifiuterà e restituirà uno stato che ti dice cosa ha fatto. È molto più flessibile che chiamare semplicemente "elimina".
Un tale oggetto non può mai essere creato in pila. Sempre sul mucchio. E la cancellazione deve essere effettuata tramite un amico o un membro. Un prodotto può utilizzare una singola gerarchia di oggetti e un gestore di memoria personalizzato - tali scenari possono utilizzare un dtor privato.
#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;
}
Quando non si desidera che gli utenti accedano al distruttore, ad esempio, si desidera che l'oggetto venga distrutto solo con altri mezzi.
http://blogs.msdn.com/larryosterman/archive/2005/07/01/434684.aspx fornisce un esempio, in cui l'oggetto viene contato come riferimento e dovrebbe essere distrutto dall'oggetto stesso quando il conteggio va a zero.
COM utilizza questa strategia per eliminare l'istanza. COM rende il distruttore privato e fornisce un'interfaccia per l'eliminazione dell'istanza.
Ecco un esempio di come sarebbe un metodo di rilascio.
int MyRefCountedObject::Release()
{
_refCount--;
if ( 0 == _refCount )
{
delete this;
return 0;
}
return _refCount;
}
Gli oggetti COM ATL sono un ottimo esempio di questo modello.
Aggiungendo alle risposte già presenti qui; i costruttori e i distruttori privati sono piuttosto utili durante l'implementazione di una fabbrica in cui è necessario allocare gli oggetti creati sull'heap. Gli oggetti sarebbero, in generale, creati / cancellati da un membro statico o un amico. Esempio di un uso tipico:
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 può essere eliminata solo da sola. Utile se si sta creando qualche tentativo di oggetto contato di riferimento. Quindi solo il metodo di rilascio può eliminare l'oggetto, aiutandoti eventualmente ad evitare errori.
So che stavi chiedendo del distruttore privato. Ecco come utilizzo quelli protetti. L'idea è che non si desidera eliminare la classe principale tramite il puntatore alla classe che aggiunge funzionalità extra alla principale.
Nell'esempio seguente non voglio che GuiWindow venga cancellato tramite un puntatore 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 è sbagliato. Ecco un esempio di oggetto con c-tor e d-tor privati creati in pila (sto usando la funzione membro statico qui, ma può essere fatto anche con la funzione amico o la classe amico).
#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);
};
Questo codice produrrà output: dentro PrivateCD :: TryMe, p._i = 8