2011-10-19 57 views
15

Meyers được đề cập trong cuốn sách của mình Hiệu quả C++ trong một số trường hợp nhất định không phải là thành viên không phải là người bạn chức năng được đóng gói tốt hơn so với chức năng thành viên.Khi nào tôi nên sử dụng các chức năng không phải là thành viên không phải thành viên đối với các chức năng của thành viên?

Ví dụ:

// Web browser allows to clear something 
class WebBrowser { 
public: 
    ... 
    void clearCache(); 
    void clearHistory(); 
    void removeCookies(); 
    ... 
}; 

Nhiều người dùng sẽ muốn thực hiện tất cả những hành động này lại với nhau, vì vậy WebBrowser cũng có thể cung cấp một chức năng để làm việc đó:

class WebBrowser { 
public: 
    ... 
    void clearEverything(); // calls clearCache, clearHistory, removeCookies 
    ... 
}; 

Một cách khác là để xác định một chức năng không phải là thành viên không phải là thành viên.

void clearBrowser(WebBrowser& wb) 
{ 
    wb.clearCache(); 
    wb.clearHistory(); 
    wb.removeCookies(); 
} 

Chức năng không phải thành viên sẽ tốt hơn vì "nó không làm tăng số lượng chức năng có thể truy cập vào phần riêng tư của lớp".

Các chức năng như clearBrowsercác chức năng tiện lợi vì chúng không thể cung cấp bất kỳ chức năng nào một cách khác. Ví dụ: nếu clearBrowser không tồn tại, khách hàng chỉ có thể gọi số clearCache, clearHistoryremoveCookies.

Với tôi, ví dụ về các chức năng tiện lợi là hợp lý. Nhưng có bất kỳ ví dụ nào khác ngoài chức năng tiện lợi khi phiên bản không phải thành viên xuất sắc không?

Nói chung, các quy tắc khi sử dụng là gì?

+4

Tôi nghĩ có nhiều tôn giáo hơn các quy tắc khách quan thực tế cho chủ đề đó. – PlasmaHH

+1

Bất kỳ loại thuật toán nào được hưởng lợi miễn phí hơn là thành viên, vì bạn có thể sử dụng lại chúng cho một phạm vi rộng hơn các đối tượng. Một ví dụ về điều này là các hàm 'begin()'/'end()' miễn phí đã được thêm vào tiêu chuẩn mới (cho phép bạn lặp lại các mảng tĩnh cũng như các thùng chứa). –

+3

@PlasmaHH: Tôi không nghĩ nó giống tôn giáo hơn. Lý do để thực hiện một số chức năng không phải là thành viên và không phải người bạn là khá hợp lý. – Nawaz

Trả lời

20

Thông thường, quy tắc khi nào nên sử dụng?

Đây là những gì quy tắc Scott Meyer là (source):

Scott có một bài viết thú vị trong in ấn mà chủ trương rằng phi thành viên chức năng phi bạn cải thiện đóng gói cho các lớp học. Ông sử dụng các thuật toán sau để xác định nơi một hàm f được đặt:

if (f needs to be virtual) 
    make f a member function of C; 
else if (f is operator>> or operator<<) 
{ 
    make f a non-member function; 
    if (f needs access to non-public members of C) 
     make f a friend of C; 
} 
else if (f needs type conversions on its left-most argument) 
{ 
    make f a non-member function; 
    if (f needs access to non-public members of C) 
     make f a friend of C; 
} 
else if (f can be implemented via C's public interface) 
    make f a non-member function; 
else 
    make f a member function of C; 

định nghĩa về đóng gói của ông liên quan đến số lượng các chức năng bị tác động khi dữ liệu cá nhân thành viên được thay đổi.

Tổng số tiền đó lên hết, và nó cũng khá hợp lý, theo ý kiến ​​của tôi.

0

Chức năng không phải thành viên thường được sử dụng khi nhà phát triển thư viện muốn viết toán tử nhị phân có thể bị quá tải trên đối số với loại lớp, vì nếu bạn đặt họ làm thành viên của lớp, bạn chỉ có thể quá tải trên đối số thứ hai (đối số thứ nhất là một đối tượng của lớp đó). Các various arithmetic operators cho complex có lẽ là ví dụ dứt khoát cho việc này.

Trong ví dụ bạn trích dẫn, động lực là một loại khác: sử dụng thiết kế ghép đôi ít nhất vẫn cho phép bạn thực hiện công việc.

Điều này có nghĩa là trong khi clearEverything có thể (và, thẳng thắn, sẽ rất có thể) được làm thành viên, chúng tôi không làm cho nó thành một bởi vì nó không phải là kỹ thuật. Điều này mua cho bạn hai điều:

  1. Bạn không phải chấp nhận trách nhiệm có phương thức clearEverything trong giao diện công cộng của mình (khi bạn giao hàng với bạn, bạn đã kết hôn với cuộc sống).
  2. Số lượng chức năng có quyền truy cập vào các thành viên private của lớp là thấp hơn, do đó mọi thay đổi trong tương lai sẽ dễ thực hiện hơn và ít có khả năng gây ra lỗi hơn.

Điều đó nói rằng, trong ví dụ cụ thể này, tôi cảm thấy khái niệm này đang được thực hiện quá xa, và cho một chức năng "vô tội" mà tôi muốn hút thành một thành viên. Nhưng khái niệm là âm thanh, và trong các tình huống "thế giới thực", nơi mọi thứ không đơn giản đến nỗi nó sẽ có ý nghĩa hơn nhiều.

3

Tôi thường chọn để xây dựng các phương thức tiện ích bên ngoài các lớp học khi chúng là ứng dụng cụ thể.

Ứng dụng này thường ở trong một ngữ cảnh khác, sau đó các công cụ thực hiện công việc bên dưới. Nếu chúng tôi đưa bạn ví dụ về trình duyệt web, 3 phương pháp rõ ràng thuộc về công cụ web vì đây là chức năng cần thiết khó triển khai ở bất kỳ nơi nào khác, tuy nhiên, ClearEverything() chắc chắn là ứng dụng cụ thể hơn. Trong trường hợp này, ứng dụng của bạn có thể có một hộp thoại nhỏ có nút rõ ràng để giúp người dùng hiệu quả hơn. Có lẽ đây không phải là một cái gì đó mà một ứng dụng khác sử dụng lại công cụ trình duyệt web của bạn sẽ muốn làm và do đó có ứng dụng trong lớp động cơ sẽ trở nên lộn xộn hơn.

Ví dụ khác là trong một thư viện toán học. Thông thường, nó có ý nghĩa để có nhiều chức năng nâng cao hơn như giá trị trung bình hoặc dẫn xuất chuẩn được triển khai như là một phần của một lớp toán học. Tuy nhiên, nếu bạn có một cách ứng dụng cụ thể để tính toán một số loại trung bình không phải là phiên bản chuẩn, nó có thể nằm ngoài lớp học của bạn và một phần của một thư viện tiện ích cụ thể cho ứng dụng của bạn.

Tôi chưa bao giờ là một fan hâm mộ lớn về các quy tắc mã hóa mạnh mẽ để thực hiện mọi thứ theo cách này hay cách khác, thường là vấn đề về ý thức hệ và nguyên tắc.

M.

0

Địa phương và cho phép lớp học cung cấp các tính năng 'đủ' trong khi duy trì đóng gói là một số điều cần xem xét.

Nếu WebBrowser được sử dụng lại ở nhiều nơi, phụ thuộc/khách hàng có thể xác định nhiều chức năng tiện lợi. Điều này giúp các lớp học của bạn (WebBrowser) gọn nhẹ và dễ quản lý.

Nghịch đảo sẽ là WebBrowser kết thúc làm hài lòng tất cả khách hàng và trở thành một số quái vật nguyên khối khó thay đổi.

Bạn có thấy lớp thiếu chức năng khi nó đã được đưa vào sử dụng trong nhiều trường hợp không? Các mẫu có xuất hiện trong các chức năng tiện lợi của bạn không? Tốt nhất (IMO) để trì hoãn chính thức mở rộng giao diện của lớp cho đến khi các mẫu xuất hiện và có một lý do chính đáng để thêm chức năng này.Một lớp tối thiểu dễ bảo trì hơn, nhưng bạn không muốn triển khai dự phòng khắp nơi bởi vì điều đó đẩy gánh nặng bảo trì lên các máy khách của bạn.

Nếu các chức năng thuận tiện của bạn phức tạp để thực hiện hoặc có trường hợp phổ biến có thể cải thiện hiệu suất đáng kể (ví dụ: để trống bộ sưu tập an toàn chỉ bằng một khóa, thay vì một phần tử tại một thời điểm với khóa mỗi lần), sau đó bạn cũng có thể muốn xem xét trường hợp đó.

Cũng sẽ có trường hợp bạn nhận ra điều gì đó thực sự bị thiếu trong số WebBrowser khi bạn sử dụng.

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