5

Gegeben:Intercept C++ implizit Copykonstruktor oder rufen Sie seine Funktionalität

class Foo { 

private: 
    static int cntFoos; 

    //... stuff... 

public: 
    Foo() { cntFoos++; } 
    ~Foo() { cntFoos--; } 
}; 

... wo „Stoff“ jeder Satz von Eigenschaften sein kann. (Die Idee ist, einen Zähler von Instanzen dieser Klasse haben)

Dann:

Foo aFoo; 
Foo twoFoo=aFoo; 

Wird die automatische Copykonstruktor aufrufen und so würde ich dieses vermissen zu zählen.

Gibt es eine Möglichkeit, den Zähler so zu speichern, dass er die automatisch erstellten neuen Instanzen wiedergibt? Wenn ich den expliziten Kopierkonstruktor implementiere, muss ich alle Eigenschaften einzeln zuweisen. Allerdings möchte ich eine flache, Memberwise-Kopie. Ich muss keine tiefe Kopie durchführen, daher scheint es unnötig, einen expliziten Kopierkonstruktor zu implementieren.

+0

Gleiche wie ein Zeiger Handling (aber nur zu zählen, hier). Nachschlage-Regel von drei (fünf C++ 11) –

+1

Überladen Sie den Kopierkonstruktor. – user2970916

Antwort

5

Da Sie das Standardverhalten für die meisten Mitglieder wollen und nur spezielle Behandlung für ein (statisches) Mitglied benötigen, warum kapseln Sie diese spezielle Behandlung in seiner eigenen Klasse nicht ein und machen Sie eine Mitgliedsvariable dieser Klasse? Wie folgt aus:

template<typename T> 
class InstanceCounter 
{ 
public: 
    static int Count; 

    // Automatically invoked when a class containing it is created. 
    InstanceCounter() { Count++; } 

    // Automatically invoked when a class containing it is destroyed. 
    ~InstanceCounter() { Count--; } 

    // Automatically invoked when a class containing it is copy-constructed. 
    InstanceCounter(const InstanceCounter& rhs) { Count++; } 

    // No need to override operator= 

    // Allow this counter to be used as an int.  
    operator int() const { return Count; } 
}; 

template<typename T> 
int InstanceCounter<T>::Count; 

class Foo 
{ 
public: 
    InstanceCounter<Foo> count; 
}; 

Hinweise zur Implementierung:

  • machte ich InstanceCounter eine Schablone, damit verschiedene Klassen leicht ihre eigene Instanz zählt haben.
  • Für C++ 11, möchten Sie auch einen Verschiebungskonstruktor und einen Verschiebungszuweisungsoperator für InstanceCounter bereitstellen.

Alternativ und wahrscheinlich besser, das CRTP Idiom mit:

template<typename T> 
class InstanceCounted 
{ 
public: 
    static int InstanceCount; 

    // Automatically invoked when a class containing it is created. 
    InstanceCounted() { InstanceCount++; } 

    // Automatically invoked when a class containing it is destroyed. 
    ~InstanceCounted() { InstanceCount--; } 

    // Automatically invoked when a class containing it is copy-constructed. 
    InstanceCounted(const InstanceCounted& rhs) { InstanceCount++; } 

    // No need to override operator= 
}; 

template<typename T> 
int InstanceCounted<T>::InstanceCount; 

class Foo : public InstanceCounted<Foo> 
{ 
    // insert class contents here 
}; 
// Now we can access Foo::InstanceCount. 
+1

Ich würde vorschlagen, Foo eine Kindklasse von InstanceCounter , für die Verwendung des CRTP-Idiom machen. – Serge

+0

Ich gebe zu, das ist wahrscheinlich eine viel bessere Lösung für das OP-Szenario. Meine Antwort versucht, die konkrete gestellte Frage direkter zu beantworten, nämlich wie man einen expliziten Kopierkonstruktor mit automatisch implementiertem seichtem Kopierverhalten erhält. Aber wenn jemand hierher kommt, um nach einer Instanz zu suchen, die die Lösung zählt, so würde ich es auch tun. –

+1

@DavidPfeffer Immer eine schwierige Entscheidung, wenn es sowohl eine Antwort gibt, die die explizite Frage beantwortet, als auch eine, die eine andere, aber bessere Lösung bietet. – Serge

5

Entschuldigung, Sie müssen überladen und von Hand kopieren.

Wenn Sie wirklich, wirklich, wirklich dagegen sind, könnten Sie einen Hack verwenden, wo Sie eine abstrakte Elternklasse mit dem statischen Zähler und überschriebenen Kopierkonstruktor erstellen, und eine Kindklasse mit Ihren tatsächlichen Datenmitgliedern und impliziter oberflächlicher Kopie Konstrukteur.

Sie können auch die etwas weniger Hacky-Ansatz einer gekapselten Klasse nehmen. Speichern Sie die Werte, die flach in die gekapselte Klasse kopiert werden sollen, und erstellen Sie dann beim Implementieren des Konstruktors für explizite Kopien der äußeren Klasse eine flache Kopie der inneren Klasse, indem Sie ihren impliziten Kopierkonstruktor verwenden.