Bởi vì, như Bjarne đặt nó, C++ được thiết kế để bảo vệ chống lại Murphy, chứ không phải Machiavelli.
Nói cách khác, nó phải bảo vệ bạn khỏi tai nạn - nhưng nếu bạn đi đến bất kỳ công việc nào để phá hoại nó (chẳng hạn như sử dụng dàn diễn viên), nó thậm chí sẽ không cố ngăn bạn lại.
Khi tôi nghĩ về nó, tôi có một suy nghĩ tương tự hơi khác: nó giống như khóa trên cửa phòng tắm. Nó cung cấp cho bạn một cảnh báo rằng bạn có thể không muốn để đi bộ trong đó ngay bây giờ, nhưng nó tầm thường để mở khóa cửa từ bên ngoài nếu bạn quyết định.
Chỉnh sửa: như câu hỏi @Xeo thảo luận, về lý do tại sao tiêu chuẩn cho biết "có cùng kiểm soát truy cập" thay vì "có tất cả kiểm soát truy cập công khai", câu trả lời dài và hơi quanh co.
Hãy bước trở lại vào đầu và xem xét một cấu trúc như:
struct X {
int a;
int b;
};
C luôn luôn có một vài quy tắc cho một cấu trúc như thế này. Một là trong thể hiện của cấu trúc, địa chỉ của cấu trúc phải bằng địa chỉ a
, vì vậy bạn có thể đưa con trỏ đến cấu trúc tới con trỏ tới int
và truy cập a
với kết quả được xác định rõ. Khác là các thành viên phải được sắp xếp theo cùng một thứ tự trong bộ nhớ khi chúng được định nghĩa trong cấu trúc (mặc dù trình biên dịch là miễn phí để chèn đệm giữa chúng).
Đối với C++, có ý định duy trì điều đó, đặc biệt là đối với các cấu trúc C hiện có. Đồng thời, có ý định rõ ràng là nếu trình biên dịch muốn thực thi private
(và protected
) vào thời gian chạy, sẽ dễ dàng thực hiện điều đó (hợp lý hiệu quả).
Do đó, một cái gì đó nhất định như:
struct Y {
int a;
int b;
private:
int c;
int d;
public:
int e;
// code to use `c` and `d` goes here.
};
Trình biên dịch nên được yêu cầu để duy trì các quy tắc tương tự như C đối với Y.a
và Y.b
với. Đồng thời, nếu nó sẽ thực thi truy cập vào thời gian chạy, nó có thể muốn di chuyển tất cả các biến công cộng cùng nhau trong bộ nhớ, vì vậy cách bố trí sẽ được nhiều hơn như:
struct Z {
int a;
int b;
int e;
private:
int c;
int d;
// code to use `c` and `d` goes here.
};
Sau đó, khi nó được thực thi điều tại Theo thời gian của tôi, về cơ bản nó có thể làm điều gì đó giống như if (offset > 3 * sizeof(int)) access_violation();
Kiến thức của tôi không ai làm được điều này, và tôi không chắc phần còn lại của tiêu chuẩn thực sự cho phép nó, nhưng dường như có ít nhất là một nửa hình thành mầm của một ý tưởng dọc theo dòng đó.
Để thực thi cả hai, C++ 98 cho biết Y::a
và Y::b
phải theo thứ tự đó trong bộ nhớ và Y::a
phải ở đầu cấu trúc (ví dụ: quy tắc giống C). Tuy nhiên, do các thông số truy cập can thiệp, Y::c
và Y::e
không còn phải theo thứ tự tương ứng với nhau.Nói cách khác, tất cả các biến liên tiếp được xác định mà không có một specifier truy cập giữa chúng được nhóm lại với nhau, trình biên dịch được tự do sắp xếp lại các nhóm đó (nhưng vẫn phải giữ lại các đầu tiên ở đầu).
Điều đó là tốt cho đến khi một số kẻ giật (tức là tôi) đã chỉ ra rằng cách các quy tắc được viết có một vấn đề nhỏ khác. Nếu tôi đã viết mã như:
struct A {
int a;
public:
int b;
public:
int c;
public:
int d;
};
... bạn đã kết thúc với một chút tự mâu thuẫn. Một mặt, điều này vẫn chính thức là cấu trúc POD, vì vậy các quy tắc giống như C được cho là sẽ áp dụng - nhưng vì bạn đã thừa nhận vô số các specifier giữa các thành viên, nó cũng cho phép trình biên dịch sắp xếp lại các thành viên, phá vỡ các quy tắc giống như C mà họ dự định.
Để khắc phục điều đó, họ đã nói lại tiêu chuẩn một chút để nói về các thành viên đều có cùng quyền truy cập, thay vì có hay không có một thông số truy cập giữa chúng. Có, họ có thể chỉ ra lệnh rằng các quy tắc sẽ chỉ áp dụng cho các thành viên công cộng, nhưng nó sẽ xuất hiện mà không ai nhìn thấy bất cứ điều gì để đạt được từ đó. Cho rằng điều này đã được sửa đổi một tiêu chuẩn hiện có với rất nhiều mã đã được sử dụng trong một thời gian, lựa chọn cho sự thay đổi nhỏ nhất mà họ có thể làm mà vẫn sẽ chữa được vấn đề.
Trong C++, thời điểm bạn sử dụng phôi như thế, bạn đã nói với trình biên dịch bạn không quan tâm đến tính an toàn và kiểm tra kiểu của nó. Đây không phải là an ninh mạng; trình biên dịch sẽ cho phép bạn làm hỏng công cụ của riêng bạn nếu bạn nhấn mạnh, như mã của bạn. – tenfour
@tenfour Có, tôi nhận ra rằng tôi hơi ngạc nhiên rằng điều đó là có thể. Tôi đã thay đổi C cast thành một static_cast và sau đó trình biên dịch đã phàn nàn. – mathematician1975
bạn thực sự không nên sử dụng C phôi trong C++. Về cơ bản họ đang nói với trình biên dịch 'biến mất, tôi biết những gì tôi đang làm, và tôi chịu mọi trách nhiệm'. Họ thậm chí còn tồi tệ hơn reinterpret_cast (mà cũng có thể đã làm việc bằng cách này. Static_cast sẽ không hoạt động vì không có cách nào cũng được xác định để làm những gì bạn đang yêu cầu) –