2008-09-24 5 views

Respuesta

76

Una forma de hacerlo sería convertir los constructores en privados y solo permitir la construcción a través de un método estático que devuelva un puntero. Por ejemplo:

class Foo 
{ 
public: 
    ~Foo(); 
    static Foo* createFoo() 
    { 
     return new Foo(); 
    } 
private: 
    Foo(); 
    Foo(const Foo&); 
    Foo& operator=(const Foo&); 
}; 
+7

+ 1 para recordar hacer que no se pueda copiar. –

+8

O mejor aún una función estática que devuelve un std :: unique_ptr . –

+0

** Pregunta relacionada: ** [¿Cómo evito que se asigne una clase a través del operador 'nuevo'? (Me gustaría asegurar que mi clase RAII esté siempre asignada en la pila.)] (Http://stackoverflow.com/questions/124856/how-do-i-prevent-a-class-from-being-allocated- via-the-new-operator-id-like) –

10

Puede hacer el constructor private, luego proporcione un método de fábrica estático public para crear los objetos.

-1

Se puede crear un archivo de cabecera que proporciona una interfaz abstracta para el objeto y las funciones de la fábrica que devuelven punteros a objetos creados en el montón.

// Header file 

class IAbstract 
{ 
    virtual void AbstractMethod() = 0; 

public: 
    virtual ~IAbstract(); 
}; 

IAbstract* CreateSubClassA(); 
IAbstract* CreateSubClassB(); 

// Source file 

class SubClassA : public IAbstract 
{ 
    void AbstractMethod() {} 
}; 

class SubClassB : public IAbstract 
{ 
    void AbstractMethod() {} 
}; 

IAbstract* CreateSubClassA() 
{ 
    return new SubClassA; 
} 

IAbstract* CreateSubClassB() 
{ 
    return new SubClassB; 
} 
14

En el caso de C++ 11

class Foo 
{ 
    public: 
    ~Foo(); 
    static Foo* createFoo() 
    { 
     return new Foo(); 
    } 

    Foo(const Foo &) = delete; // if needed, put as private 
    Foo & operator=(const Foo &) = delete; // if needed, put as private 
    Foo(Foo &&) = delete; // if needed, put as private 
    Foo & operator=(Foo &&) = delete; // if needed, put as private 

    private: 
    Foo(); 
}; 
+5

Como Scott Meyers declaró en "Elemento 11: Prefiere las funciones eliminadas a las indefinidas privadas". En su libro "Effective Modern C++", es mejor declarar las funciones de miembros eliminadas 'public'. --QUOTE-- "Por convención, las funciones eliminadas se declaran' públicas', no 'privadas'. Hay una razón para eso. Cuando el código del cliente intenta usar una función miembro, C + + verifica la accesibilidad antes de eliminar el estado. Cuando el código del cliente intenta usar una función 'privada 'eliminada, algunos compiladores se quejan solo de que la función es' privada', aunque la accesibilidad de la función realmente no afecta si se puede usar. –

+4

--QUOTE-- "Vale la pena tener esto en cuenta al revisar el código heredado para reemplazar las funciones de miembro' privadas' y no definidas con las eliminadas, porque hacer que las nuevas funciones sean 'públicas' generalmente dará como resultado mejores mensajes de error. " –

+1

Deba. Dar. Moar. Arriba. Votos. – kevinarpe

4

El siguiente permite constructores públicos y se detendrá asignaciones de pila lanzando en tiempo de ejecución. La nota thread_local es una palabra clave C++ 11.

class NoStackBase { 
    static thread_local bool _heap; 
protected: 
    NoStackBase() { 
     bool _stack = _heap; 
     _heap = false; 
     if (_stack) 
      throw std::logic_error("heap allocations only"); 
    } 
public: 
    void* operator new(size_t size) throw (std::bad_alloc) { 
     _heap = true; 
     return ::operator new(size); 
    } 
    void* operator new(size_t size, const std::nothrow_t& nothrow_value) throw() { 
     _heap = true; 
     return ::operator new(size, nothrow_value); 
    } 
    void* operator new(size_t size, void* ptr) throw() { 
     _heap = true; 
     return ::operator new(size, ptr); 
    } 
    void* operator new[](size_t size) throw (std::bad_alloc) { 
     _heap = true; 
     return ::operator new[](size); 
    } 
    void* operator new[](size_t size, const std::nothrow_t& nothrow_value) throw() { 
     _heap = true; 
     return ::operator new[](size, nothrow_value); 
    } 
    void* operator new[](size_t size, void* ptr) throw() { 
     _heap = true; 
     return ::operator new[](size, ptr); 
    } 
}; 

bool thread_local NoStackBase::_heap = false; 
+0

No creo que necesite '_stack' como miembro de datos. Tenerlo como una simple variable de pila dentro del constructor 'NoStackBase' debería hacer. –

+0

Tampoco es necesario que el destructor sea 'virtual'. Nadie puede eliminar una clase derivada a través de 'NoStackBase' de todos modos. –

Cuestiones relacionadas