2010-02-01 31 views
5

Có lý do nào cho lớp triển khai được sử dụng trong thành ngữ pimpl để có bất kỳ thành viên riêng nào không? Lý do duy nhất tôi thực sự có thể nghĩ đến là tự bảo vệ bản thân - tức là các thành viên tư nhân phục vụ thực thi một số loại hợp đồng giữa lớp và người dùng, và trong trường hợp này, lớp và người dùng có quan hệ mật thiết hơn, vì vậy nó có vẻ không cần thiết.Thành viên riêng tư trong lớp học pimpl?

+2

Giả sử thực hiện gộp cho chuỗi chỉ đọc, lớp triển khai có thể rất có tính tham chiếu để biết khi nào cần giải phóng bộ nhớ, nếu được yêu cầu. – dirkgently

+0

dirkgently: Tôi sẽ tưởng tượng rằng, để có một số duy nhất cho tất cả các tham chiếu đến một chuỗi, số đó sẽ phải được lưu trữ tập trung, trong chuỗi và không phải là trình bao bọc. Tôi đang thiếu gì ở đây? –

+0

@Steven Sudit: Bởi vì nó sẽ vi phạm thiết kế - số lượng tham chiếu nghiêm túc nói không phải là một phần của cấu trúc dữ liệu cần thiết để đại diện cho chuỗi. – dirkgently

Trả lời

10

I nghĩ rằng mọi người đang bối rối Pimpl thành ngữ với Bộ điều hợp/Cầu/Chiến lược mẫu. Thành ngữ cụ thể cho một ngôn ngữ. Các mẫu có thể áp dụng cho nhiều ngôn ngữ.

Thành ngữ Pimpl được đưa ra để giải quyết vấn đề sau trong C++: Các thành viên riêng của một lớp được hiển thị trong khai báo lớp, điều này bổ sung thêm #include phụ thuộc không cần thiết cho người dùng của lớp. Thành ngữ này còn được gọi là tường lửa trình biên dịch.

Nếu thực hiện được ghi trực tiếp trong tệp * .cpp tương ứng của lớp bên ngoài và không thể truy cập bên ngoài mô-đun, thì Tôi nghĩ nó hoàn toàn ổn khi chỉ sử dụng cấu trúc cho lớp Pimpl. Tiếp tục tái thực thi ý tưởng cho rằng việc triển khai không có nghĩa là để được trực tiếp sử dụng lại, tôi xác định chúng như là một struct nội tin:

// foo.h 
class Foo : boost::noncopyable 
{ 
public: 
    ... 

private: 
    struct Impl; 
    boost::scoped_ptr<Impl> impl_; 
}; 

// foo.cpp 
struct Foo::Impl 
{ 
    // Impl method and member definitions 
}; 

// Foo method definitions 

Ngay sau khi có một tập tin tiêu đề cho lớp thực hiện, tôi nghĩ chúng ta không còn nói về thành ngữ Pimpl nữa. Chúng tôi đang nói về các lớp Adapter, Bridge, Strategy, giao diện, v.v ...

Chỉ 2 xu của tôi.

2

Tại sao không nên có các thành viên riêng tư? Chỉ vì bạn đang định nghĩa một giao diện vì PIMPL không có nghĩa là bạn sẽ không có thời gian nào khác muốn sử dụng lớp đó.

Vẫn là lớp học. Dữ liệu có thể là riêng tư hoặc được bảo vệ. Các hoạt động trên dữ liệu sẽ không bao giờ được truy cập công khai, riêng tư hoặc được bảo vệ. Các hoạt động mà bạn có thể muốn phơi bày, bảo vệ hoặc công khai.

+0

Lý do chính của tôi vì không muốn các thành viên tư nhân là lười biếng tuyệt đối - tôi không muốn cung cấp cho người truy cập. Tôi nhận ra rằng cũng có thể có các thành viên cần riêng tư và không yêu cầu người truy cập. – Anne

+4

Nó thực sự là một lớp "tư nhân" - chỉ có thể truy cập trong một tệp cpp. Cấu trúc kiểu C chỉ tốt cho mục đích trong hầu hết các trường hợp. –

+0

Nemanja: Điều này giả định bên ngoài và bên trong được viết cùng một lúc. Tôi đã thêm pimpl sau khi thực tế để hiện thực hiện. –

4

Về lý thuyết, một lớp học pimpl vẫn chỉ là một lớp như bất kỳ lớp nào khác. Đó là việc triển khai thực hiện cụ thể một giao diện không có nghĩa là mã khác không phải là một ứng dụng khách của lớp pimpl.

Điều đó nói rằng, trong thực tế tôi đã thấy rằng các lớp pimpl có xu hướng gần gũi hơn với cấu trúc với một số hàm thành viên hơn là các đối tượng chính thức và ít cần tách giao diện khỏi triển khai.

6

Tùy thuộc vào việc triển khai pImpl của bạn - cụ thể là khi bạn thực thi bất biến lớp, nhưng nói chung tôi không cần phần impl để có các thành viên được bảo vệ/riêng tư. Trong thực tế, tôi thường tuyên bố nó như là một cấu trúc.

0

(Tôi hiểu lầm câu hỏi, vì vậy tôi thay đổi câu trả lời của tôi.)

Các lớp thực hiện, được trỏ đến bởi lớp với pimpl, phải là một lớp thông thường, với lý do cũng giống như nhiều để ẩn các chi tiết cá nhân như bất kỳ chi tiết nào khác. Trong thực tế, nó thường là một lớp có sẵn, với lớp pimpl được thêm vào sau để phá vỡ các phụ thuộc và có lẽ đơn giản hóa giao diện một chút.

+0

Lớp đã tồn tại từ trước là lớp "bên ngoài", không phải là phần "impl". –

+0

Tôi đã nhìn thấy nó đi cả hai cách. Đôi khi pimpl là một cách để đặt một giao diện nhất quán trên các triển khai có thể thay đổi. Các thời điểm khác, pimpl là một cách để ẩn hoàn toàn việc triển khai thực hiện, phá vỡ các phụ thuộc thời gian biên dịch. Trong thực tế, cả hai đều có thể là mục tiêu. –

1

Lý do duy nhất tôi thực sự có thể nghĩ đến là để bảo vệ mình khỏi chính mình

Đó là lý do tại sao "private" và "bảo vệ" đang có ở nơi đầu tiên. Tất nhiên bạn nên sử dụng chúng trong thực hiện của bạn - thời gian duy nhất tôi sẽ không được nếu việc thực hiện không có hành vi (trong trường hợp đó nó không thực sự là một thực hiện).

0

private có nghĩa là đóng gói dữ liệu tốt hơn.

Có vẻ như ngớ ngẩn, tôi biết, nhưng chúng ta có một cách để xác định các giao diện tại nơi làm việc đó là rất đơn giản:

class Interface; 

class Concrete { public: .... private: Interface* m_interface; } 

class ConcreteFoo: public Interface {}; 

Ưu điểm chính: bạn có thể trao đổi cho ConcreteBar khác bất cứ lúc nào. Trên thực tế, sự kết hợp của mẫu PimplStrategy và hàm tạo của Concrete sẽ gọi số Factory sẽ chịu trách nhiệm phân phối đối tượng hiệu quả.

Nếu bạn không thể nghĩ ra cách thứ hai để triển khai trái tim, hãy đóng gói nó trong một lớp học.Bằng cách này, nếu sau này bạn phải cấu trúc lại, bạn sẽ chỉ cần tạo một tập hợp trừu tượng Interface với cùng một tập hợp phương pháp, thay đổi một vài con trỏ (và hàm khởi tạo) và bạn sẽ ổn thỏa;)

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