Có một vấn đề rất thực tế xảy ra với các thư viện được chia sẻ mà thành ngữ ma cô có thể hiểu được một cách gọn gàng mà các thủ thuật thuần túy không làm được: bạn không thể sửa đổi / xóa các thành viên dữ liệu của một lớp một cách an toàn mà không buộc người dùng của lớp đó phải biên dịch lại mã của họ. Điều đó có thể được chấp nhận trong một số trường hợp, nhưng không phải đối với thư viện hệ thống.
Để giải thích vấn đề một cách chi tiết, hãy xem xét mã sau trong thư viện / tiêu đề được chia sẻ của bạn:
// header
struct A
{
public:
A();
// more public interface, some of which uses the int below
private:
int a;
};
// library
A::A()
: a(0)
{}
Trình biên dịch phát ra mã trong thư viện được chia sẻ để tính toán địa chỉ của số nguyên được khởi tạo thành một phần bù nào đó (có thể là 0 trong trường hợp này, vì nó là thành viên duy nhất) từ con trỏ đến đối tượng A mà nó biết là this
.
Về phía người dùng của mã, new A
trước tiên a sẽ cấp phát sizeof(A)
byte bộ nhớ, sau đó đưa một con trỏ tới bộ nhớ đó cho hàm A::A()
tạo nhưthis
.
Nếu trong bản sửa đổi sau này của thư viện, bạn quyết định loại bỏ số nguyên, làm cho nó lớn hơn, nhỏ hơn hoặc thêm các thành viên, sẽ có sự không khớp giữa lượng mã của người dùng bộ nhớ phân bổ và sự chênh lệch mà mã phương thức mong đợi. Kết quả có thể là một sự cố, nếu bạn may mắn - nếu bạn kém may mắn hơn, phần mềm của bạn hoạt động một cách kỳ lạ.
Bằng cách pimpl'ing, bạn có thể thêm và xóa các thành viên dữ liệu vào lớp bên trong một cách an toàn, khi cấp phát bộ nhớ và lệnh gọi hàm tạo diễn ra trong thư viện được chia sẻ:
// header
struct A
{
public:
A();
// more public interface, all of which delegates to the impl
private:
void * impl;
};
// library
A::A()
: impl(new A_impl())
{}
Tất cả những gì bạn cần làm bây giờ là giữ cho giao diện công cộng của bạn không có các thành viên dữ liệu khác ngoài con trỏ đến đối tượng triển khai và bạn sẽ an toàn trước lớp lỗi này.
Chỉnh sửa: Tôi có thể nên nói thêm rằng lý do duy nhất tôi đang nói về hàm tạo ở đây là tôi không muốn cung cấp thêm mã - lập luận tương tự áp dụng cho tất cả các hàm truy cập thành viên dữ liệu.