Một cách sử dụng thông thường là cấp quyền truy cập vào các chức năng tạo thành một phần của giao diện của lớp, nhưng nhờ các quy tắc khác thực sự không thể là một phần của lớp. Trình chèn / trích xuất cho iostream là một ví dụ cổ điển:
namespace whatever {
class something {
// ...
friend std::ostream &operator<<(std::ostream &os, something const &thing);
friend std::istream &operator>>(std::istream &is, something &thing);
};
}
Làm cho các thành viên toán tử của lớp sẽ không hoạt động. Một thao tác I / O trông giống như:
whatever::something thing;
std::cout << thing;
Đối với một toán tử được triển khai như một hàm thành viên, điều này sẽ được giải quyết như sau:
std::cout.operator<<(thing);
Tức là, chức năng sẽ phải là một thành viên std::cout
, không phải của something
. Vì chúng tôi không muốn sửa đổi std::ostream
liên tục, tùy chọn hợp lý duy nhất của chúng tôi là quá tải toán tử với chức năng miễn phí thay vì chức năng thành viên. Điều đó cho chúng ta hai khả năng: hoặc bỏ qua việc đóng gói hoàn toàn, và làm cho mọi thứ trong lớp trở nên công khai, hoặc nếu không thì giữ kín, nhưng cấp quyền truy cập vào một vài điều thực sự cần nó.
Làm cho một lớp khác một người bạn là khá ít phổ biến. Trong trường hợp này, bạn thường tạo ra một cái gì đó theo thứ tự của một mô-đun hoặc hệ thống con - một tập hợp các lớp hoạt động cùng nhau và có một số mức độ truy cập đặc biệt với nhau mà không được cấp cho thế giới nói chung.