2016-06-20 16 views
0

Ich war auf der Suche, wie Pimpl in C++ zu verwenden, und ich fand dieses Stück Code in einem Tutorial:Warum verwenden wir "neu" in pimpl?

// In MyClass.h 

class MyClassImp;     // forward declaration of Pimpl 

class MyClass 
{ 
public: 
    MyClass(); 
    ~MyClass(); 

    MyClass(const MyClass &rhs); // undefined for simplicity 
    MyClass& operator=(MyClass); 

    void Public_Method(); 

private: 
    MyClassImp *pimpl_;    // the Pimpl 
}; 

// In MyClass.cpp 

#include "MyClass.h" 

class MyClassImp 
{ 
public: 
    void Private_Method() {} // dummy private function 

    int private_var_;   // a private variable 
}; 

MyClass::MyClass() : pimpl_(new MyClassImp()) 
{ 
} 

MyClass::~MyClass() 
{ 
    delete pimpl_; 
} 

void MyClass::Public_Method() 
{ 
    pimpl_->Private_Method();  // do some private work 

    pimpl_->private_var_ = 3; 
} 

Aber ich konnte meinen Kopf nicht mit dem Grunde der Verteilung der MyClassImp in dem Haufen herumkommen Können wir nicht einfach eine Variable auf dem Stack verwenden?

Zur Klarstellung:

Wenn wir MyClassImp in einer getrennten .h und CPP-Datei setzen, und enthalten die .h in MyClass.h und MyClassImp pimpl_ verwenden; (ohne den Zeiger), würde es nicht den gleichen Effekt erzielen? Wenn die Implementierung von MyClassImp geändert wird, muss der Aufrufer (MyClass) nicht geändert und neu kompiliert werden. (Sie müssen immer noch neu verknüpfen)

+2

* Welcher * Stapel? Der von 'MyClass :: MyClass'? Das wird zerstört, sobald der Konstruktor fertig ist. Der des Anrufers? * Sie kennen den Anrufer nicht. * – DevSolar

+1

Fragen Sie, warum Sie 'MyClassImp * pimpl_ haben müssen; 'anstelle von' MyClassImp pimpl_; '? – NathanOliver

+1

Um "auf dem Stapel" zu adressieren - innerhalb des Stapelrahmens von welchem ​​Funktionsaufruf möchten Sie es haben? Und um zu erfahren, warum die automatische Speicherdauer nicht verwendet wird - der Hauptpunkt der Übung ist es, die Definition von "MyClassImp" zu verbergen. Wenn es ein direktes Mitglied wäre, müsste seine Größe (und damit seine Definition) bekannt sein. – Angew

Antwort

1

Sie müssen eine neue aufgrund des Zeigers tun. Der Zeiger existiert, so dass Sie die Definition von Impl weiterleiten (d. H. Nicht einschließen) können. Wenn Sie die Definition von Impl in Ihre Kopfzeile einschließen, legen Sie sie für jede Datei offen, die sie enthält.

5

Der Trick des Pimpl-Idioms ist, dass in Ihrer Header-Datei nur ein Zeiger verwendet wird. Dies bedeutet, dass Sie eine Forward-Deklaration der Klasse verwenden können, ohne eine Deklaration abzugeben.

Sie könnten später Ihre Deklaration (in der cpp) ändern, ohne Ihre Kopfzeile oder andere Kompilierungseinheiten mit Ihrer Kopfzeile zu beeinflussen.

Dies ist besonders nützlich im Umgang mit Bibliotheken.

+0

Wenn wir einfach MyClassImp pimpl_ verwenden und MyClassImp in separate Dateien einfügen, muss MyClassImp.h in MyClass.h eingeschlossen werden, wenn dies der Fall ist eine Änderung an MyClassImp, muss MyClass.h nicht neu replizieren? – user1701840

+0

Solange Sie nur die Implementierung von MyClassImp ändern, ja - aber wenn Sie auch die Schnittstelle (= Header) ändern, müssen Sie neu kompilieren. Mit einem Zeiger können Sie völlig frei machen, was Sie wollen, da Sie nicht einmal MyClassImp.h einschließen – Anedar

1

Das grundlegende Problem besteht darin, dass der Code die Größe der impl-Klasse am aufrufenden Standort kennen muss, um die Impl auf den Stack zu setzen, was bedeutet, dass die Klassendefinition der impl angezeigt werden müsste. Der ganze Sinn des Impls ist verstecken die Klassendefinition.

Verwandte Themen