2009-04-07 52 views
6

Có thích hợp để truy cập các thành viên riêng của một lớp bằng cách truyền nó thành một con trỏ rỗng và sau đó đến một cấu trúc?Truy cập các thành viên riêng

Tôi không nghĩ mình có quyền sửa đổi lớp chứa các thành viên dữ liệu mà tôi cần truy cập. Tôi không muốn mạo hiểm truy cập vào các thành viên dữ liệu theo cách gián tiếp nếu nó không mang tính đạo đức.

CHỈNH SỬA: Đã phải chỉnh sửa thêm nữa ... Tôi khá chắc chắn lớp học sẽ không được sửa đổi, vì vậy nó ok cho mức độ đó ... mối quan tâm duy nhất của tôi là, nếu người mã hóa lớp đó được biết điều này, nó có thể không đi xuống tốt với anh ấy :(

+0

Cụ thể, bạn đang cố gắng thực hiện điều này bằng cách làm điều này? –

Trả lời

6

"Không bao giờ nói không bao giờ". Tôi chắc chắn một nơi nào đó trong vũ trụ, có một tình huống sẽ buộc bạn phải làm điều này ...

Nhưng tôi chắc chắn sẽ rạn nứt nếu tôi phải làm điều đó. Bạn thực sự cần nhận được rất nhiều ý kiến ​​về tình hình của bạn trước khi kéo cò. Bạn có thể mô tả tình hình cụ thể của bạn và có lẽ chúng ta có thể thấy nó có ý nghĩa hay không, những lựa chọn thay thế nào tốt hơn có thể tồn tại?

Để trả lời nhận xét/câu hỏi - Xác định "quyền" - sự cho phép của tổ chức? Điều đó nghe có vẻ không phải là một vấn đề lập trình, nhưng một cái gì đó để nói chuyện với bất cứ ai đang khẳng định cho phép. Có lẽ đây là vấn đề chính trị hơn là vấn đề kỹ thuật? Một lần nữa, tôi nghĩ chúng ta cần thêm chi tiết cụ thể - ngay cả khi nó có phần về chính trị của tình hình. Điều đó có thể hoặc có thể không được coi là ngoài phạm vi cho trang web, tuy nhiên.

+0

Tôi nghĩ rằng tôi đã đề cập rằng trong câu hỏi .. Tôi không có quyền truy cập vào định nghĩa đó, nhưng tôi cần một thành viên được định nghĩa trong lớp đó để tính toán một số giá trị. – Shree

+2

vứt bỏ lớp học đó và sử dụng lớp học cung cấp quyền truy cập vào thành viên. –

+0

Đó sẽ là một lớp khác. Nó không có quyền truy cập vào thành viên mong muốn. – southerton

26

tôi không chắc chắn rằng "đạo đức" thực sự đi vào nó nó bán thân các heck ra khỏi đóng gói mặc dù

EDIT:... tôi sẽ gần như không bao giờ chấp nhận điều này nếu tôi đang thực hiện đánh giá mã.Bạn sẽ phải làm việc thực sự khó thuyết phục tôi không có cách nào thiết kế xung quanh nhu cầu này. Có thể bạn sẽ succ eed, nhưng phải có những cảnh báo lớn trên khắp nơi, và thử nghiệm đơn vị đá cứng để đảm bảo rằng nếu bất cứ điều gì thay đổi để phá vỡ nó, bạn sẽ biết một cách nhanh chóng.

+0

đó là sự thật, nhưng nếu bạn không có cách nào khác để làm điều đó, người ta có thể phải buông bỏ một số khái niệm? – Shree

+0

Sự đóng gói không thực sự ở đó để bảo vệ khỏi bị lạm dụng. Đôi khi, đây là cách duy nhất để đi :-( –

+0

Nếu đó là một lớp người mà bạn đang vi phạm, thì có những mối quan tâm chính về đạo đức :-) – veefu

3

Đó là đạo đức, nhưng thường có nhiều mã bẩn bên cạnh hành vi không xác định và tính không thể di chuyển. Làm điều đó chỉ khi bạn hoàn toàn phải làm.

+0

Mọi người rất tự do (đọc 'lười') khi xác định vị trí của đường "hoàn toàn phải". –

+0

Đúng, và điều này dẫn đến một loạt các câu hỏi phỏng vấn đơn giản nhưng thú vị giúp chỉ thuê những người có mức độ lười biếng cần thiết. – sharptooth

+0

Có. Đối với cả người phỏng vấn và ứng cử viên. –

9

No. Điều bạn đang làm là Pure Evil.

+0

Xin chào, bạn đã đánh cắp các thẻ vô hình của mình từ http://stackoverflow.com/questions/722350/should-your-opensource-project-attempt-to-mimic-commercial-products. – chaos

+0

Tôi nghĩ rằng thẻ vô hình là nguồn mở! –

5

Nếu bạn cảm thấy sự thôi thúc để làm điều này, quên đúc - chỉ cần sửa đổi khai báo lớp trong file header:

class A { 
    private: 
    int x; 
}; 

sự thay đổi đó để:

class A { 
    public: 
    int x; 
}; 

và bạn tốt để đi . Vâng, có lẽ "tốt" không phải là từ đúng.

+0

tại sao không đề cập đến việc vi phạm ODR. nó cũng đi từ không POD đến POD. tôi tưởng tượng cơ hội là tốt hơn một cái gì đó phá vỡ sau đó. như nó là viết tắt, người ta có thể đọc câu trả lời của bạn là "bạn chỉ có thể làm ... nó sẽ làm việc" –

+0

Chỉ cần nhớ rằng trong khi chơi roulette Nga, một lần như vậy thường xuyên viên đạn bắn. –

+0

Nó chỉ phá vỡ ODR nếu định nghĩa của A nằm trong thư viện. Và tôi không hoàn toàn nghiêm túc ... –

2

Ah, trừu tượng - bạn không thể sống mà không có nó nhưng nó là như vậy đau đớn để đối phó với đôi :)

Dù sao, đạo đức sang một bên, những gì nếu "chủ sở hữu" của lớp quyết định thay đổi nội thực hiện, hoặc đơn giản là đảo ngược thứ tự của các thành viên dữ liệu cá nhân?

+0

Thường chỉ gây đau đớn nếu bạn vặn nó lên. –

+0

@ John rất đúng! +1 –

1

Câu trả lời đơn giản: Số

Nó không mang tính đạo đức và nó sẽ trở thành cơn ác mộng duy trì tại một số điểm. Các thành viên tư nhân nội bộ của thư viện có thể thay đổi và phá vỡ mã của bạn.Các nhà phát triển của thư viện không cần phải biết (cũng không muốn) rằng bạn đang vi phạm việc đóng gói.

Các lớp thường có bất biến so với phương thức của chúng mà một số lần sẽ không được ghi lại, nhưng việc truy cập và thay đổi các giá trị từ bên ngoài có thể phá vỡ những bất biến đó. Ví dụ, nếu bạn thay đổi không gian dành riêng trong một véc-tơ có giá trị cao hơn, vectơ sẽ không phân bổ không gian mới cho đến khi nó lấp đầy hiện tại và điều đó sẽ không xảy ra trước khi nhấn bộ nhớ chưa được phân bổ: ứng dụng của bạn sẽ bị lỗi.

Nếu thuộc tính là riêng tư, nó không dành cho bạn để sử dụng nó, chỉ cho chính lớp hoặc bạn bè của lớp biết về thành viên, cách sử dụng nó, cách không phá vỡ nó. Nếu lập trình viên muốn bạn thay đổi trường, nó sẽ được công khai.

+0

Đã chấp nhận ... đây là lý do tôi đã hỏi câu hỏi này ... nhưng có cách nào khác để truy cập vào các thành viên không? Ít nhất tôi không thể nghĩ ra được ... – Shree

+0

Nếu không có thêm thông tin về vấn đề thực sự, tôi không thể nói. Nhưng tôi nghĩ rằng có thể bạn muốn giải quyết vấn đề của mình từ góc nhìn khác với thông tin bạn có về lớp học. –

27

Chúng ta không xem xét đạo đức trong một khoảnh khắc. Hãy xem xét tiêu chuẩn.

Những gì bạn đang đề xuất làm là không chuẩn. Xem phần 9.2, khoản 12 của tiêu chuẩn. "Thứ tự phân bổ các thành viên không phải được phân tách bởi một trình xác định truy cập không được chỉ định." Vì vậy, nếu bạn có một lớp học với các thành viên tư nhân, và một cấu trúc không có thành viên riêng, tiêu chuẩn không đảm bảo rằng các thành viên sẽ theo cùng thứ tự.

Vì vậy, nếu hack của bạn hoạt động, nó chỉ hoạt động một cách tình cờ, mà các nhà biên dịch đã tình cờ làm như vậy. Không có gì đảm bảo rằng nó sẽ làm việc trên một trình biên dịch khác, một phiên bản sau của cùng một trình biên dịch, hoặc với các bố cục lớp khác nhau. Chưa kể, nếu bạn không có thẩm quyền sửa đổi lớp (nói, để cung cấp một hàm truy cập đơn giản), bạn có thể không có thẩm quyền để phản đối nếu bất kỳ chi tiết triển khai nào trong lớp thay đổi. (Một trong những ý tưởng đằng sau công cộng và riêng tư là để phân biệt những gì được hứa từ những gì có thể thay đổi được.) Vì vậy, cách bố trí có thể thay đổi hoặc thành viên có thể có ý nghĩa gì đó khác hoặc bị loại bỏ hoàn toàn.

Herb Sutter đã viết a Guru of the Week cột về vấn đề này.

Ồ, theo đạo đức thì sao? Nếu bạn thực sự, thực sự phải làm một cái gì đó như thế này, và bạn không thể có được ra khỏi nó, tài liệu đó rất cẩn thận. Nếu các tiêu chuẩn mã hóa của bạn có một số loại thủ tục để gắn cờ hành vi không chuẩn, hãy sử dụng chúng. Nếu không, phải rất cẩn thận để lưu ý nó trong một cách nó sẽ không được bỏ qua khi một cái gì đó đi sai.

+0

Thích ý kiến ​​của bạn :) – Shree

+0

Tham chiếu thực sự thú vị với GoTW. Tôi sẽ upvote một lần nữa nếu tôi có thể. –

+0

Cảm ơn bạn rất nhiều ... Tôi đã sẵn sàng để đào ra bản sao của tiêu chuẩn và kiểm tra các khoản phân bổ cho bảo lãnh. Công việc thám tử rất đẹp. –

6

Tôi đã xảy ra điều này với tôi vì có một hệ thống kiểm soát nguồn rất khốc liệt thay cho phiên bản cũ của ứng dụng thực hiện thay đổi đối với tệp tiêu đề là điều không thể thực hiện được.

Nếu một số trường hợp bạn chỉ cần thực hiện hack.

Trong tập tin nguồn mà từ đó bạn cần truy cập vào dữ liệu cá nhân thành viên bạn có thể đưa vào điều này như một dòng đầu tiên:

#define private public 
#define protected public 

và truy cập vào bất cứ điều gì bạn muốn.

+0

Tôi nghĩ rằng tôi nên thử điều này, nhưng một lần nữa có thể không mang tính đạo đức. Nhưng có, như bạn đã nói, trong một số trường hợp nó chỉ là không thể sửa đổi một số mã. – Shree

1

Vấn đề "đạo đức" duy nhất là những gì bạn đang làm với người khốn nghèo, người sẽ phải tìm ra và duy trì mã của bạn.

Thành viên riêng tư chỉ là vậy. Anh ta có thể, và rất có thể, một ngày nào đó sẽ thay đổi thành viên đó. Khi điều đó xảy ra, bạn có thể thậm chí không nhận thấy vì có nhiều khả năng vẫn sẽ là bộ nhớ ở đó, chỉ cần không phải là thành viên bạn mong đợi. Damn gần bất kỳ điều gần như không thể bạn có thể tưởng tượng có thể sau đó bắt đầu xảy ra khi mã của bạn được chạy. Làm thế nào là ai sẽ có thể gỡ lỗi đó?

12

Tôi vừa thêm một số entry to my blog cho biết cách thực hiện theo cách hoàn toàn phù hợp. Dưới đây là một ví dụ về cách bạn sử dụng nó cho các lớp sau

struct A { 
private: 
    int member; 
}; 

Chỉ cần khai báo một tên thẻ và nhanh chóng một tên cướp giống như ví dụ chương trình sau đây (bài viết của tôi cho thấy việc thực hiện cướp). Sau đó, bạn có thể truy cập thành viên đó bằng cách sử dụng con trỏ thành viên

struct Amem { typedef int type; }; 
template class rob<Amem, &A::member>; 

int main() { 
    A a; 
    a.*result<Amem>::ptr = 42; // Doh! 
} 

Nhưng thực tế, điều này không cho thấy quy tắc truy cập của C++ không đáng tin cậy. Các quy tắc ngôn ngữ được thiết kế để bảo vệ chống lại những sai lầm ngẫu nhiên - nếu bạn cố gắng cướp dữ liệu của một đối tượng, ngôn ngữ theo thiết kế không mất nhiều thời gian để ngăn bạn.


Trên đây là một cách để truy cập thành viên private và được bảo vệ một cách phù hợp. Đây là một cách khác để truy cập được bảo vệ thành viên theo cách phù hợp tiêu chuẩn. Ý tưởng cơ bản là sử dụng con trỏ thành viên

std::deque<int> &getAdapted(std::stack<int> &s) { 
    struct voyeur : stack<int> 
    { using stack<int>::c; }; 
    return s.*(&voyeur::c); 
} 

int main() { 
    std::stack<int> s; 
    std::deque<int> &adapted = getAdapted(s); 
    output(adapted); // print the stack... 
} 

Không tham gia hoặc loại tham gia. Phải mất một con trỏ đến một thành viên được bảo vệ của std::stack<int> thông qua một lớp có nguồn gốc từ nó, nơi mà tên thành viên là công khai, vì vậy trình biên dịch cho phép điều này. Sau đó, nó sử dụng nó trên một đối tượng std::stack<int>, cũng được cho phép.

0

Tôi giả định rằng lớp học này là một phần của dự án bạn đang làm việc.

Có một vấn đề đạo đức ở đây: Nếu trong công ty của bạn, bạn thấy quyền sở hữu mã là yếu đuối. Hoặc tệ nhất là bạn không được phép sửa đổi mã không phải là mã của bạn. Có Bạn có thể làm tổn thương cảm giác của người duy trì lớp học đó. Hoặc tức giận anh ta nếu lương của anh ta liên quan đến mã của anh ta. tốt nhất là chỉ yêu cầu anh ta giúp đỡ, và một số gợi ý, ví dụ như. thêm chức năng getter hoặc thay đổi riêng tư thành công khai - tất cả đều dựa trên trực giác của bạn khi sử dụng mã mới đó.

Hack mà bạn đã đề cập thực sự là giường thực hành. Nếu không thể sửa đổi mã và người bảo trì đó sẽ không thay đổi bất cứ điều gì. Xem xét sử dụng mẫu thiết kế bộ điều hợp.

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