5

Given:Intercept C++ ngầm constructor sao chép, hoặc gọi chức năng của nó

class Foo { 

private: 
    static int cntFoos; 

    //... stuff... 

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

... nơi "công cụ" có thể bất kỳ tập hợp tài sản. (Ý tưởng là để có một bộ đếm của trường của lớp đó)

Sau đó:

Foo aFoo; 
Foo twoFoo=aFoo; 

sẽ gọi constructor sao chép tự động, và do đó em lại nhớ đếm thế này.

Có cách nào để giữ bộ đếm phản ánh các phiên bản mới được tạo tự động không? Nếu tôi thực hiện hàm tạo bản sao rõ ràng, tôi sẽ phải gán tất cả các thuộc tính một. Tuy nhiên, tôi muốn bản sao nông, thành viên. Tôi không cần phải thực hiện một bản sao sâu, do đó, nó có vẻ như rất nhiều công việc không cần thiết để thực hiện một nhà xây dựng bản sao rõ ràng.

+0

Tương tự như xử lý một con trỏ (nhưng chỉ cần đếm, ở đây). Tra cứu quy tắc ba (năm C++ 11) –

+1

Quá tải hàm tạo bản sao. – user2970916

Trả lời

5

Vì bạn muốn hành vi mặc định cho hầu hết các thành viên và chỉ cần xử lý đặc biệt cho một thành viên (tĩnh), tại sao không đóng gói xử lý đặc biệt đó trong lớp của riêng mình và tạo biến thành viên của lớp đó? Như thế này:

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

ghi chú thực hiện:

  • tôi đã InstanceCounter một mẫu để các lớp khác nhau có thể dễ dàng có tội dụ riêng của họ.
  • Đối với C++ 11, bạn cũng sẽ muốn cung cấp hàm tạo di chuyển và toán tử gán di chuyển cho InstanceCounter.

Ngoài ra, và có lẽ tốt hơn, sử dụng thành ngữ 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

Tôi sẽ đề nghị làm cho Foo một lớp con của InstanceCounter , để sử dụng thành ngữ CRTP. – Serge

+0

Tôi sẽ thừa nhận, đây có lẽ là giải pháp tốt hơn cho kịch bản thực tế của OP. Câu trả lời của tôi cố gắng trả lời trực tiếp câu hỏi cụ thể hơn, đó là cách để có được một hàm tạo bản sao rõ ràng với hành vi sao chép nông được triển khai tự động. Nhưng nếu có ai đến đây tìm kiếm một giải pháp đếm cá thể, thì đây là cách tôi cũng làm như vậy. –

+1

@DavidPfeffer Luôn là một quyết định khó khăn khi có cả câu trả lời trả lời câu hỏi rõ ràng, cũng như câu trả lời cung cấp giải pháp khác nhưng tốt hơn. – Serge

5

Rất tiếc, bạn sẽ cần phải quá tải và sao chép bằng tay. Nếu bạn thực sự, thực sự, thực sự chống lại điều này, bạn có thể sử dụng hack nơi bạn tạo một lớp cha trừu tượng với bộ đếm tĩnh và hàm khởi tạo sao chép đã ghi đè và lớp con với các thành viên dữ liệu thực tế của bạn và bản sao nông cạn constructor.

Bạn cũng có thể sử dụng phương pháp tiếp cận ít hacky hơn của lớp được đóng gói. Lưu trữ các giá trị bạn muốn sao chép nông trong lớp đóng gói và sau đó khi thực hiện hàm tạo bản sao rõ ràng lớp bên ngoài, tạo một bản sao nông của lớp bên trong bằng cách sử dụng hàm tạo bản sao ẩn của nó.

Các vấn đề liên quan