C++ cho phép private thành viên được thay đổi bằng cách sử dụng phương pháp này tại sao?


0 Phiếu
Đã hỏi 24/4/2016 bởi pbzIf (490 điểm)
Sau khi nhìn thấy câu hỏi này một vài phút trước, tôi tự hỏi tại sao các nhà thiết kế ngôn ngữ cho phép nó vì nó cho phép các thay đổi gián tiếp của dữ liệu private . Như là một ví dụ
 class TestClass {
   private:
    int cc;
   public:
     TestClass(int i) : cc(i) {};
 };
 TestClass cc(5);
 int* pp = (int*)&cc;
 *pp = 70;             // private member has been modified
tôi thử nghiệm trên code và thực sự private data đã bị thay đổi. Là có bất kỳ lời giải thích tại sao điều này cho phép xảy ra hay đây chỉ là một giám sát trong ngôn ngữ? Có vẻ như để trực tiếp làm suy yếu sử dụng private data thành viên.

3 Câu trả lời

0 Phiếu
Đã trả lời 29/4/2016 bởi Npg_2281_Dys (172,880 điểm)
Vì backwards-tương thích với C, nơi bạn có thể làm điều tương tự.
cho tất cả mọi người tự hỏi, đây là lý do tại sao điều này không phải là UB và thực sự được cho phép bởi các tiêu chuẩn: trước tiên, TestClass là một tiêu chuẩn giao diện class (§9 [class] p7):
A bố trí tiêu chuẩn class là một class rằng:
  • đã không có thành viên-tĩnh data type Phi standard bố trí class (hoặc mảng của các loại như vậy) hoặc tham khảo, / / OK:-tĩnh data member là type 'int'
  • đã không có chức năng ảo (10.3) và không có các lớp học ảo cơ sở (10.1), / / OK
  • có cùng access control (khoản 11) cho tất cả các thành viên-tĩnh data , / / OK, tất cả các thành viên data tĩnh (1) là 'tư nhân'
  • đã không có phi standard bố trí các lớp cơ sở, / / OK, không có các lớp học cơ sở
  • đã không có thành viên-tĩnh data ở class nhất có nguồn gốc và nhiều nhất một cơ sở class với các thành viên-tĩnh data , hoặc đã không có các lớp học cơ sở với các thành viên-tĩnh data , và / / OK, cơ sở không có các lớp học lại
  • đã không có các lớp học cơ sở của type tương tự như các thành viên-tĩnh data đầu tiên. / / OK, cơ sở không có các lớp học lại
và với điều đó, bạn có thể được phép reinterpret_cast class để type member đầu tiên của nó (§9.2 [class.mem] p20):
A c8310e4cc8b11c6ac 103 d00194407081 đến một đối tượng tiêu chuẩn bố trí struct, phù hợp chuyển đổi bằng cách sử dụng một reinterpret_cast, trỏ đến member đầu tiên của nó (hoặc nếu member đó là một chút-lĩnh vực, sau đó đến unit , mà nó cư trú) và ngược lại.
trong trường hợp của bạn, các diễn viên (int*) C-phong cách giải quyết cho một reinterpret_cast (§5.4 [expr.cast] p4).
+1 Phiếu
Đã trả lời 11/5/2016 bởi r5780 (180 điểm)
Vì backwards-tương thích với C, nơi bạn có thể làm điều tương tự.
cho tất cả mọi người tự hỏi, đây là lý do tại sao điều này không phải là UB và thực sự được cho phép bởi các tiêu chuẩn: trước tiên, TestClass là một tiêu chuẩn giao diện class (§9 [class] p7):
A bố trí tiêu chuẩn class là một class rằng:
  • đã không có thành viên-tĩnh data type Phi standard bố trí class (hoặc mảng của các loại như vậy) hoặc tham khảo, / / OK:-tĩnh data member là type 'int'
  • đã không có chức năng ảo (10.3) và không có các lớp học ảo cơ sở (10.1), / / OK
  • có cùng access control (khoản 11) cho tất cả các thành viên-tĩnh data , / / OK, tất cả các thành viên data tĩnh (1) là 'tư nhân'
  • đã không có phi standard bố trí các lớp cơ sở, / / OK, không có các lớp học cơ sở
  • đã không có thành viên-tĩnh data ở class nhất có nguồn gốc và nhiều nhất một cơ sở class với các thành viên-tĩnh data , hoặc đã không có các lớp học cơ sở với các thành viên-tĩnh data , và / / OK, cơ sở không có các lớp học lại
  • đã không có các lớp học cơ sở của type tương tự như các thành viên-tĩnh data đầu tiên. / / OK, cơ sở không có các lớp học lại
và với điều đó, bạn có thể được phép reinterpret_cast class để type member đầu tiên của nó (§9.2 [class.mem] p20):
A pointer đối tượng tiêu chuẩn bố trí struct, phù hợp chuyển đổi bằng cách sử dụng một reinterpret_cast, trỏ đến member đầu tiên của nó (hoặc nếu member đó là một chút-lĩnh vực, sau đó đến unit , mà nó cư trú) và ngược lại.
trong trường hợp của bạn, các diễn viên (int*) C-phong cách giải quyết cho một reinterpret_cast (5b96357617992bc0ee8f366 103 27f379).
0 Phiếu
Đã trả lời 11/5/2016 bởi benno (430 điểm)
Bởi vì, như Bjarne đặt nó, C++ được thiết kế để bảo vệ chống Murphy, không Machiavelli. Nói cách khác, đó là nghĩa vụ để bảo vệ bạn khỏi tai nạn... nhưng nếu bạn đi đến bất kỳ làm việc ở tất cả để subvert (chẳng hạn như bằng cách sử dụng một diễn viên) nó sẽ thậm chí không cố gắng để ngăn chặn bạn. Khi tôi nghĩ về nó, tôi có một tương tự hơi khác nhau trong tâm trí: nó cũng 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ộ ở đó ngay bây giờ, nhưng nó là 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 thảo luận, về lý do tại sao các tiêu chuẩn nói "có quyền kiểm soát access cùng" thay vì "có tất cả public access kiểm soát", câu trả lời là dài và quanh co một chút. Hãy bước trở lại để bắt đầu và xem xét một struct như:
struct X {
    int a;
    int b;
};
C luôn luôn có một vài quy tắc cho cách struct như thế này. Một là trong một instance struct, address struct chính nó đã bằng address của a, do đó, bạn có thể cast một pointer để struct để pointer để int, và access a với kết quả cũng được định nghĩa. Một là các thành viên phải được sắp xếp theo thứ tự trong bộ nhớ như họ được định nghĩa trong struct (mặc dù compiler là miễn phí để chèn đệm giữa chúng). Cho c + +, đã có một mục đích duy trì, đặc biệt là đối với hiện tại C structs. Cùng lúc đó, đã có một ý định rõ ràng rằng nếu compiler muốn thực thi private (và protected) tại thời gian chạy, nó cần được dễ dàng để làm điều đó (hợp lý một cách hiệu quả). Vì vậy, được đưa ra một cái gì đó như:
struct Y { 
    int a;
    int b;
private:
    int c;
    int d;
public:
    int e;
    // code to use `c` and `d` goes here.
};
compiler nên được yêu cầu để duy trì các quy tắc tương tự như C đối với Y.aY.b. Cùng lúc đó, nếu nó sẽ thực thi access tại thời gian chạy, nó có thể di chuyển tất cả các biến public cùng nhau trong bộ nhớ, do đó, việc bố trí sẽ 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ó thực thi điều tại thời gian chạy, nó có thể cơ bản làm một cái gì đó như if (offset > 3 * sizeof(int)) access_violation(); kiến thức của tôi không ai bao giờ làm điều này, và tôi không chắc chắn phần còn lại của các tiêu chuẩn thực sự cho phép nó , nhưng có vẻ như đã là ít nửa hình thành mầm một ý tưởng dọc theo dòng. Để thực hiện cả hai của những người, C ++ 98 nói Y::aY::b đã theo thứ tự đó trong bộ nhớ, và Y::a đã tại đầu của struct (tức là, giống như C quy tắc). Tuy nhiên, vì can thiệp access specifiers, Y::cY::e không còn có để theo thứ tự liên quan đến nhau. Nói cách khác, tất cả các liên tiếp biến xác định mà không có một specifier access giữa họ được gộp nhóm cùng nhau, compiler đã được tự do để sắp xếp lại các nhóm (nhưng vẫn còn có để giữ cho những người đầu tiên vào đầu). Đó là tiền phạt cho đến khi một số jerk (tức là tôi) chỉ ra rằng cách thức các quy tắc được viết đã có một vấn đề nhỏ khác. Nếu tôi đã viết code giống như:
struct A { 
    int a;
public:
    int b;
public:
    int c;
public:
    int d;
};
.. .anh đã kết thúc với một chút chút tự contradition. Một mặt, đây là vẫn chính thức một struct POD, do đó, các quy tắc như C đã phải áp dụng--nhưng kể từ khi bạn đã có (admittedly vô nghĩa) access specifiers giữa các thành viên, nó cũng cho phép compiler để sắp xếp lại các thành viên, do đó phá vỡ quy tắc C như họ dự định. Để chữa bệnh, họ tái worded các tiêu chuẩn một chút vì vậy nó sẽ nói về các thành viên tất cả có quyền truy cập cùng, chứ không phải là về việc có hay không có là một specifier access giữa chúng. Vâng, họ có thể có chỉ cần quyết định rằng các quy tắc sẽ chỉ áp dụng cho các thành viên public , nhưng nó sẽ xuất hiện rằng không ai nhìn thấy bất cứ điều gì để có được từ đó. Cho rằng đây cách thay đổi một tiêu chuẩn hiện có với nhiều code đã được sử dụng cho khá trong một, chọn tham gia cho sự thay đổi nhỏ nhất họ có thể làm cho rằng vẫn sẽ chữa vấn đề.

ToughDev Q&A là gì?

Trang web hỏi đáp cho các bạn đam mê lập trình, phát triển phần mềm và các vấn đề kỹ thuật khác. Với sự giúp đỡ của bạn, chúng tôi hy vọng sẽ xây dựng thành công một thư viện đầy đủ các câu hỏi và trả lời về tất cả các vấn đề có liên quan đến lập trình!







...