2009-03-10 8 views

Respuesta

139

Básicamente, cada vez que desee que otra clase sea responsable del ciclo de vida de los objetos de su clase o tenga motivos para evitar la destrucción de un objeto, puede hacer que el destructor sea privado.

Por ejemplo, si está haciendo un tipo de recuento de referencia, puede hacer que el objeto (o administrador que ha sido "amigo") sea responsable de contar el número de referencias a sí mismo y eliminarlo cuando el número llega a cero. Un dtor privado evitaría que alguien más lo borre cuando todavía hay referencias al mismo.

Para otra instancia, ¿qué sucede si tiene un objeto que tiene un administrador (o sí mismo) que puede destruirlo o puede rechazar destruirlo según otras condiciones del programa, como una conexión de base de datos abierta o un archivo siendo escrito. Puede tener un método "request_delete" en la clase o el administrador que verificará esa condición y lo eliminará o rechazará, y devolverá un estado que le indicará qué hizo. Eso es mucho más flexible que solo llamar a "eliminar".

+3

ver guidline # 4 http://www.gotw.ca/publications/mill18.htm – Eric

+2

Este aswer faltan algunos ejemplo de código. – mrgloom

5

La clase solo se puede eliminar por sí misma. Útil si está creando alguna prueba de objeto contado de referencia. Entonces, solo el método de lanzamiento puede eliminar el objeto, posiblemente ayudándole a evitar errores.

55

Tal objeto nunca se puede crear en la pila. Siempre en el montón. Y la eliminación debe hacerse a través de un amigo o un miembro. Un producto puede usar una única jerarquía de Objetos y un administrador de memoria personalizado; dichos escenarios pueden usar un controlador privado.

#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; 
} 
+1

La eliminación se debe hacer a través de un amigo/o miembro/ – MSalters

+0

Esto ya fue mencionado, así que me lo salté. Will updata (en la segunda lectura, mi afirmación parece demasiado fuerte). – dirkgently

+12

Corrección: Tal objeto * puede * crearse en la pila (pero solo en el ámbito de un amigo o de sí mismo). –

2

Podría ser una manera de lidiar con el problema de Windows, donde cada módulo puede usar un montón diferente, como la Debug montón. Si ese problema no se maneja correctamente badthings puede suceder.

3

Sé que estabas preguntando sobre el destructor privado. Aquí es cómo uso los protegidos. La idea es que no desee eliminar la clase principal a través del puntero a la clase que agrega funcionalidad adicional a la principal.
En el siguiente ejemplo, no quiero que GuiWindow se elimine a través de un puntero 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(){} 
}; 
15

COM utiliza esta estrategia para eliminar la instancia. COM hace que el destructor sea privado y proporciona una interfaz para eliminar la instancia.

Aquí hay un ejemplo de cómo sería un método de versión.

int MyRefCountedObject::Release() 
{ 
_refCount--; 
if (0 == _refCount) 
{ 
    delete this; 
    return 0; 
} 
return _refCount; 
} 

ATL COM objects son un excelente ejemplo de este patrón.

+0

Instructivo. ¡Gracias! –

3

dirkgently está mal. Aquí hay un ejemplo de objeto con c-tor y d-tor privados creados en la pila (aquí estoy usando la función de miembro estático, pero también se puede hacer con la función de amigo o la clase de amigo).

#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); 
}; 

Este código producirá salida: dentro PrivateCD :: Tryme, p._i = 8

+2

Estoy bastante seguro de que dirkgently significa que el código que * usa * su clase no puede crear una instancia de la clase en la pila. Por supuesto, aún puede crear una instancia de la clase en la pila * dentro de los métodos de * clase, ya que en ese contexto puede acceder a miembros privados. –

5

Agregando a las respuestas ya aquí presentes; los constructores privados y los destructores son bastante útiles al implementar un factory donde se requiere que los objetos creados se asignen en el montón. Los objetos serían, en general, creados/eliminados por un miembro estático o amigo. Ejemplo de un uso típico:

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 
}