2008-09-24 3 views

Antwort

76

Eine Möglichkeit wäre, die Konstruktoren privat zu machen und nur die Konstruktion über eine statische Methode zuzulassen, die einen Zeiger zurückgibt. Zum Beispiel:

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

+ 1 für die Erinnerung, um es nicht kopierbar zu machen. –

+8

Oder noch besser eine statische Funktion, die ein std :: unique_ptr zurückgibt. –

+0

** Verwandte Frage: ** [Wie verhindere ich die Zuweisung einer Klasse über den Operator 'new'? (Ich möchte sicherstellen, dass meine RAII-Klasse immer auf dem Stapel zugeordnet ist.)] (Http://stackoverflow.com/questions/124856/how-doi-i-prevent-a-class-from-being-alloated-) via-the-new-operator-id-artig) –

10

Sie könnten den Konstruktor private erstellen und dann eine statische Factory-Methode public zum Erstellen der Objekte bereitstellen.

-1

Sie könnten eine Header-Datei erstellen, die eine abstrakte Schnittstelle für das Objekt zur Verfügung stellt und Fabrik-Funktionen, die Zeiger auf Objekte erstellt auf dem Heap zurück.

// 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

Im Fall von 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

Wie Scott Meyers in "Punkt 11: Gelöschte Funktionen an private undefinierte bevorzugen." sein Buch "Effective Modern C++" ist es besser, gelöschte Mitgliederfunktionen "public" zu deklarieren. --QUOTE-- "Per Konvention werden gelöschte Funktionen als' public', nicht als 'private' deklariert. Es gibt einen Grund dafür. Wenn Client-Code versucht, eine Member-Funktion zu verwenden, prüft C + + die Barrierefreiheit vor dem gelöschten Status versucht, eine gelöschte "private" -Funktion zu verwenden, beschweren sich einige Compiler nur über die Funktion "private", obwohl die Zugänglichkeit der Funktion nicht wirklich Einfluss darauf hat, ob sie verwendet werden kann. " –

+4

--QUOTE-- "Es ist wichtig, dies bei der Überarbeitung von Legacy-Code zu berücksichtigen, um' private' und nicht definierte Mitgliedsfunktionen durch gelöschte zu ersetzen, da die neuen Funktionen 'public' im Allgemeinen zu besseren Fehlermeldungen führen. " –

+1

Muss. Geben. Moar. Oben. Stimmen. – kevinarpe

4

Nachstehend ermöglicht öffentliche Konstruktoren und wird durch das Werfen zur Laufzeit Stapelzuordnungen stoppen. Hinweis thread_local ist ein C++ 11-Schlüsselwort.

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

Ich glaube nicht, dass Sie '_stack' als Datenelement benötigen. Es sollte eine einfache Stapelvariable innerhalb des 'NoStackBase'-Konstruktors sein. –

+0

Sie müssen den Destruktor auch nicht virtuell machen. Niemand kann eine abgeleitete Klasse trotzdem über eine 'NoStackBase' löschen. –

Verwandte Themen