2010-03-16 44 views
5

Khi bạn chuẩn bị in một đối tượng, một toán tử bạn bè < < được sử dụng. Chúng tôi có thể sử dụng chức năng thành viên cho nhà điều hành < <?Tại sao chức năng bạn bè được ưu tiên cho chức năng thành viên cho toán tử <<

class A { 

public: 
void operator<<(ostream& i) { i<<"Member function";} 
friend ostream& operator<<(ostream& i, A& a) { i<<"operator<<"; return i;} 
}; 


int main() { 

    A a; 
    A b; 
    A c; 
    cout<<a<<b<<c<<endl; 
    a<<cout; 
    return 0; 
} 

Một điểm là chức năng bạn cho phép chúng tôi sử dụng nó như thế này

cout<<a<<b<<c 

gì lý do khác?

+3

Bạn có thực sự cần bất kỳ lý do nào khác không? –

+0

@mmyers: Tôi chỉ cố gắng hiểu nó rõ ràng như tôi có thể. – skydoor

+1

Nó rõ ràng không thể là một chức năng thành viên (xem câu trả lời của Charles Bailey), nhưng nó không phải là một người bạn * * - nếu bạn có thể thực hiện nó dưới dạng giao diện công khai của lớp, điều đó sẽ siêu. – UncleBens

Trả lời

11

Bạn phải sử dụng chức năng miễn phí chứ không phải chức năng thành viên đối với các toán tử nhị phân bên tay trái luôn là *this cho các chức năng thành viên với phía bên tay phải được chuyển làm tham số khác.

Đối với các toán tử luồng đầu, bên trái luôn là đối tượng luồng, vì vậy nếu bạn đang phát trực tuyến đến lớp chuẩn và không tự viết luồng, bạn phải cung cấp chức năng miễn phí chứ không phải là thành viên của lớp học.

Mặc dù nó sẽ có thể cung cấp cho một nhà điều hành dòng ngược như một hàm thành viên và dòng ra như thế này:

myObject >> std::cout; 

không chỉ bạn sẽ vi phạm một quy ước thư viện rất mạnh mẽ, như bạn chỉ ra, dí đầu ra hoạt động sẽ không hoạt động do nhóm từ trái sang phải >>.

Edit: Như những người khác đã lưu ý, trong khi bạn có để làm cho nó một chức năng miễn phí nó chỉ cần là một friend nếu chức năng streaming không thể được thực hiện trong điều kiện của lớp public interface.

10

Bạn không có lựa chọn nào - nó phải là một chức năng miễn phí.

Lưu ý, tuy nhiên, nó không nhất thiết phải là hàm friend. Nó chỉ cần là một người bạn nếu bạn thực sự cần cấp quyền truy cập riêng tư. Ví dụ, tôi sử dụng những điều sau đây trong các cuộc thi lập trình:

template <class A, class B> 
std::ostream& operator<<(std::ostream& os, const std::pair<A, B>& p) 
{ 
    return os << '(' << p.first << ", " << p.second << ')'; 
} 

Không cần phải cho nó trở thành người bạn, như firstsecond có thể truy cập công khai.

1

Một lý do nữa trong ví dụ của bạn - nó phải là một friend vì đó là cách duy nhất để xác định một hàm miễn phí bên trong định nghĩa lớp. Nếu bạn muốn có một chức năng không phải là bạn bè, nó sẽ phải được định nghĩa bên ngoài lớp.

Tại sao bạn muốn xác định nó trong lớp học? Đôi khi nó là tốt đẹp để xác định tất cả các nhà khai thác với nhau:

struct SomeClass { 
    // blah blah blah 
    SomeClass &operator+=(const SomeClass &rhs) { 
     // do something 
    } 
    friend SomeClass operator+(SomeClass lhs, const SomeClass &rhs) { 
     lhs += rhs; 
     return lhs; 
    } 
    // blah blah blah 
    // several pages later 
}; 

có thể thêm một chút thân thiện hơn:

struct SomeClass { 
    // blah blah blah 
    SomeClass &operator+=(const SomeClass &rhs) { 
     // do something 
    } 
    // blah blah blah 
    // several pages later 
}; 

SomeClass operator+(SomeClass lhs, const SomeClass &rhs) { 
    lhs += rhs; 
    return lhs; 
} 

này giả định tất nhiên mà bạn đang định chức năng thành viên có liên quan trong định nghĩa lớp , thay vì tuyên bố chúng ở đó và định nghĩa chúng trong tệp .cpp.

Chỉnh sửa: Tôi đã sử dụng + = và + làm ví dụ mà không thực sự nghĩ về nó, nhưng câu hỏi của bạn là về operator<<, không có bất kỳ nhà khai thác liên quan chặt chẽ nào như operator+. Nhưng nếu operator<< gọi một hoặc nhiều chức năng thành viên liên quan đến in, bạn có thể muốn xác định nó gần nơi chúng được xác định.

0

Bạn không thể. Nhưng nếu bạn không muốn nó trở thành một chức năng kết bạn, hãy làm cho nó trở thành một chức năng miễn phí và thực hiện nó theo giao diện công khai của lớp. Ví dụ:

ostream& operator<<(ostream& os, Myclass& obj) 
{ 
    return obj.print(os); 
} 

ostream& MyClass::print(ostream& os) 
{ 
    os << val; // for example. 
    return os; 
} 
Các vấn đề liên quan