2009-07-17 41 views
30

Có sự khác biệt nào giữa việc xác định toán tử toàn cục có hai tham chiếu cho một lớp và xác định toán tử thành viên chỉ có toán hạng phải không?Sự khác nhau giữa toán tử toàn cục và toán tử thành viên

toàn cầu:

class X 
{ 
public: 
    int value; 
}; 

bool operator==(X& left, X& right) 
{ 
    return left.value == right.value; 
}; 

Thành viên:

class X 
{ 
    int value; 
    bool operator==(X& right) 
    { 
     return value == right.value; 
    }; 
} 
+2

Đó là thực hành tốt để khai báo đối số không chỉ tham khảo, nhưng cũng const, bất cứ khi nào bạn chắc chắn bạn có thể. Các toán tử so sánh có thể là const và lấy tham chiếu const cho chắc chắn. (Nếu không có gì khác, nó hứa với trình biên dịch cho phép nó tối ưu hơn.) –

Trả lời

39

Một lý do để sử dụng toán tử không phải thành viên (thường được khai báo là bạn bè) là vì bên trái- bên tay là một trong những hoạt động. Obj::operator+ là tốt cho:

obj + 2 

nhưng đối với:

2 + obj 

nó sẽ không hoạt động. Đối với điều này, bạn cần một cái gì đó như:

class Obj 
{ 
    friend Obj operator+(const Obj& lhs, int i); 
    friend Obj operator+(int i, const Obj& rhs); 
}; 

Obj operator+(const Obj& lhs, int i) { ... } 
Obj operator+(int i, const Obj& rhs) { ... } 
5

Có ít nhất một sự khác biệt. Một nhà điều hành thành viên có thể truy cập các công cụ sửa đổi và có thể công khai, được bảo vệ hoặc riêng tư. Biến thành viên toàn cầu không bị hạn chế sửa đổi truy cập.

Điều này đặc biệt hữu ích khi bạn muốn vô hiệu hóa các nhà khai thác nhất định như phân

class Foo { 
    ... 
private: 
    Foo& operator=(const Foo&); 
}; 

Bạn có thể đạt được hiệu quả tương tự bằng việc có một chỉ điều hành toàn cầu công bố. Nhưng nó sẽ dẫn đến lỗi liên kết so với lỗi biên dịch (nipick: có nó sẽ dẫn đến lỗi liên kết trong Foo)

+0

Một toán tử toàn cầu được khai báo sẽ không liên kết (tức là không có chương trình), trong khi một toán tử thành viên sẽ làm điều đó. Chỉ sử dụng bất hợp pháp của các thành viên tư nhân sẽ gây ra một lỗi biên dịch. Chính xác? –

6

lựa chọn thông minh nhất của bạn là để làm cho nó một chức năng bạn.

Như JaredPar đề cập, việc triển khai toàn cầu không thể truy cập các thành viên lớp học được bảo vệ và riêng tư, nhưng cũng có vấn đề với chức năng thành viên.

C++ sẽ cho phép chuyển đổi ngầm định các thông số chức năng, nhưng không cho phép chuyển đổi ẩn của this.

Nếu loại tồn tại mà có thể được chuyển đổi sang lớp X của bạn:

class Y 
{ 
public: 
    operator X(); // Y objects may be converted to X 
}; 


X x1, x2; 
Y y1, y2; 

Chỉ một số các biểu thức sau đây sẽ biên dịch với một hàm thành viên.

x1 == x2; // Compiles with both implementations 
x1 == y1; // Compiles with both implementations 
y1 == x1; // ERROR! Member function can't convert this to type X 
y1 == y2; // ERROR! Member function can't convert this to type X 

Các giải pháp, để có được sản phẩm tốt nhất của cả hai thế giới, là để thực hiện điều này như một người bạn:

class X 
{ 
    int value; 

public: 

    friend bool operator==(X& left, X& right) 
    { 
     return left.value == right.value; 
    }; 
}; 
+1

Đó không phải là lỗi, đó là một tính năng;) Tôi ghét các chuyển đổi tiềm ẩn ... –

6

Tóm lại câu trả lời bằng cách Codebender:

khai thác thành viên không đối xứng. Trình biên dịch không thể thực hiện cùng một số thao tác với các toán tử bên tay trái và bên phải.

struct Example 
{ 
    Example(int value = 0) : value(value) {} 
    int value; 

    Example operator+(Example const & rhs); // option 1 
}; 
Example operator+(Example const & lhs, Example const & rhs); // option 2 
int main() 
{ 
    Example a(10); 
    Example b = 10 + a; 
} 

Trong mã ở trên sẽ không biên dịch nếu nhà điều hành là hàm thành viên trong khi nó hoạt động như mong đợi nếu nhà điều hành là một chức năng miễn phí.

Nói chung một mô hình chung đang triển khai các nhà khai thác phải có chức năng thành viên là thành viên và phần còn lại là miễn phí chức năng mà đại biểu vào các nhà khai thác thành viên:

class X 
{ 
public: 
    X& operator+=(X const & rhs); 
}; 
X operator+(X lhs, X const & rhs) 
{ 
    lhs += rhs; // lhs was passed by value so it is a copy 
    return lhs; 
} 
Các vấn đề liên quan