5

Dane:Intercept C++ niejawna kopia konstruktor, lub wywołać jego funkcjonalność

class Foo { 

private: 
    static int cntFoos; 

    //... stuff... 

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

... gdzie "rzeczy" może być dowolny zestaw właściwości. (Chodzi o to, aby mieć licznik wystąpień tej klasy)

wówczas:

Foo aFoo; 
Foo twoFoo=aFoo; 

wywoła konstruktor automatycznego kopiowania, a więc ja tęsknię licząc tego.

Czy istnieje sposób na zachowanie tego licznika odzwierciedlającego automatycznie nowe wystąpienia? Jeśli zaimplementuję konstruktora jawnej kopii, będę musiał przypisać wszystkie właściwości jeden po drugim. Jednak I chce mieć płytką, zgodną z oryginałem kopię. Nie muszę wykonywać głębokiej kopii, więc wydaje się, że wiele niepotrzebnej pracy wymaga implementacji jawnego konstruktora kopii.

+0

Taka sama jak obsługa wskaźnik (ale tylko licząc, tutaj). Wyszukaj regułę trzech (pięć C++ 11) –

+1

Przeciążenie konstruktora kopiowania. – user2970916

Odpowiedz

5

Ponieważ chcesz zachować domyślne zachowanie większości członków i potrzebujesz tylko specjalnej obsługi dla jednego (statycznego) elementu, dlaczego nie obudować tej specjalnej obsługi w jej własnej klasie i utworzyć zmienną składową tej klasy? Tak:

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

notatek realizacji:

  • zrobiłem InstanceCounter szablonu tak, że różne klasy mogą łatwo mieć własne liczniki instancji.
  • Dla C++ 11, należy również podać konstruktor ruchu i operator przypisania ruchu dla InstanceCounter.

Alternatywnie, i chyba lepiej, używając idiomu CRTP:

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

Sugerowałbym uczynienie Foo klasą potomną InstanceCounter , do używania idiomu CRTP. – Serge

+0

Przyznam, że jest to prawdopodobnie znacznie lepsze rozwiązanie dla rzeczywistego scenariusza PO. Moja odpowiedź próbuje bardziej bezpośrednio odpowiedzieć na postawione pytanie, czyli jak uzyskać konstruktor jawnej kopii z automatycznie zaimplementowanym zachowaniem płytkiej kopii. Ale jeśli ktoś przyjdzie tutaj, szukając rozwiązania do liczenia instancji, to tak też bym to zrobił. –

+1

@DavidPfeffer Zawsze trudna decyzja, gdy istnieje zarówno odpowiedź, która odpowiada na jednoznaczne pytanie, jak i taka, która zapewnia inne, ale lepsze rozwiązanie. – Serge

5

Przepraszamy, trzeba będzie ręcznie przeciążyć i skopiować.

Jeśli naprawdę, naprawdę, wbrew temu, można użyć hacka, w którym tworzy się abstrakcyjną klasę macierzystą z licznikiem statycznym i nadpisanym konstruktorem kopiowania, oraz klasę podrzędną z rzeczywistymi członkami danych i niejawną płytką kopią konstruktor.

Możesz także przyjąć nieco mniej hackowatą postawę zamkniętej klasy. Zapisz wartości, które mają być płytko skopiowane w klasie zamkniętej, a następnie podczas implementacji konstruktora jawnej kopii zewnętrznej, utwórz płytką kopię klasy wewnętrznej, używając jej niejawnego konstruktora kopiowania.