2010-06-26 39 views
7

Tôi biết tôi có thể tự mình trả lời câu hỏi này một cách dễ dàng bằng mã generatin và xem nó có biên dịch hay không. Nhưng vì tôi không thể tìm thấy một câu hỏi tương tự, tôi nghĩ đó là kiến ​​thức đáng để chia sẻ. Giả sử tôi đang quá tải toán tử + cho MyClass. Tôi có thể quá tải nó nhiều lần không. Quá tải khác nhau cho các loại khác nhau. Như thế này:C++ quá tải nhiều toán tử cho cùng một toán tử

class MyClass{ 
... 
inline const MyClass operator+(const MyClass &addend) const { 
    cout<<"Adding MyClass+MyClass"<<endl; 
    ...//Code for adding MyClass with MyClass 
} 
inline const MyClass operator+(const int &addend) const { 
    cout<<"Adding MyClass+int"<<endl; 
    ...//Code for adding MyClass with int 
} 
... 
}; 
int main(){ 
    MyClass c1; 
    MyClass c2; 
    MyClass c3 = c1 + c2; 
    MyClass c4 = c1 + 5; 
} 
/*Output should be: 
    Adding MyClass+MyClass 
    Adding MyClass+in*/ 

Lý do tôi muốn làm điều này là tôi đang xây dựng một lớp học mà tôi muốn được tối ưu nhất có thể. Hiệu suất là mối quan tâm lớn nhất đối với tôi ở đây. Vì vậy, đúc và sử dụng trường hợp chuyển đổi bên trong các nhà điều hành + chức năng quá tải không phải là một lựa chọn. Tôi e bạn sẽ nhận thấy, tôi đã thực hiện cả hai tình trạng quá tải nội tuyến. Giả sử rằng trình biên dịch thực sự nhấn mạnh quá tải của tôi, sau đó nó được xác định trước tại thời gian biên dịch mã sẽ chạy, và tôi lưu cuộc gọi đến một hàm (bằng nội tuyến) + trường hợp chuyển đổi phức tạp (trong thực tế, sẽ có 5+ quá tải cho toán tử +), nhưng tôi vẫn có thể viết mã dễ đọc bằng cách sử dụng toán tử số học cơ bản. Vì vậy, tôi sẽ nhận được hành vi mong muốn?

+0

Nếu bạn quan tâm đến hiệu suất, từ quan điểm của lớp, trả về '* this' thông qua' const Myclass & 'sẽ tốt hơn. Bây giờ, từ quan điểm của người dùng (trừ khi bạn đang biên soạn trên C++ 0x), bạn nên sử dụng '+ =' thay vì '+' và '=' để tránh các thời gian vô dụng có thể sẽ không được tối ưu hóa bởi một số crappy trình biên dịch. – paercebal

+0

Tôi không biết tại sao điều này lại bị bỏ phiếu. Đó là một câu hỏi hoàn toàn hợp lệ.(Thực tế là bạn tìm thấy thông tin này ở nơi khác cũng không có lý do gì để không tìm thấy câu trả lời ở đây nữa.) – sbi

+3

@paercebal: Ông đang thực hiện một khoản tiền chứ không phải là khoản tăng. Nếu anh ta đang thực thi 'operator + =', sau đó trả về một tham chiếu sẽ là tốt (sau khi sửa đổi trạng thái bên trong), nhưng 'a + b' không có nghĩa là sửa đổi' a', mà là tạo ra giá trị thứ ba khác với cả hai 'a' và' b'. –

Trả lời

8

Dạng thức thực thi kinh điển operator+() là một chức năng miễn phí dựa trên operator+=(), mà người dùng của bạn sẽ mong đợi khi bạn có +. += thay đổi đối số bên trái của nó và do đó phải là thành viên. Các + xử lý đối số của nó đối xứng, và do đó sẽ là một chức năng miễn phí.

Something như thế này nên làm:

//Beware, brain-compiled code ahead! 
class MyClass { 
public: 
    MyClass& operator+=(const MyClass &rhs) const 
    { 
     // code for adding MyClass to MyClass 
     return *this; 
    } 
    MyClass& operator+=(int rhs) const 
    { 
     // code for adding int to MyClass 
     return *this; 
    } 
}; 


inline MyClass operator+(MyClass lhs, const MyClass& rhs) { 
    lhs += rhs; 
    return lhs; 
} 
inline MyClass operator+(MyClass lhs, int rhs) { 
    lhs += rhs; 
    return lhs; 
} 
// maybe you need this one, too 
inline MyClass operator+(int lhs, const MyClass& rhs) { 
    return rhs + lhs; // addition should be commutative 
} 

(Lưu ý rằng hàm thành viên định nghĩa với lớp định nghĩa của họ là ngầm inline Cũng lưu ý, rằng trong vòng MyClass, tiền tố MyClass:: hoặc là không cần thiết hoặc thậm chí sai..)

+1

+1 cho đúng biểu mẫu. Tuy nhiên tôi có thể sử dụng Boost.Operators để tạo ra các chức năng miễn phí :) –

+0

Qn rất cơ bản: Định nghĩa của bạn cho + yêu cầu lhs là một const trong khi mã yêu cầu bạn viết lhs + = rhs. Có vẻ như bạn cần phải thay đổi mã của bạn hoặc định nghĩa của bạn. Tôi có đúng không? – vad

+0

@Anon: Đó là một sự xáo trộn lớn của tôi. '' Tôi đã đến và sửa nó, và nắm lấy cơ hội để thêm tuyên bố từ chối trách nhiệm tiêu chuẩn của tôi. – sbi

9

Có.


Các chức năng này chỉ là các chức năng thông thường với tên đặc biệt [email protected]. Không có hạn chế mà họ không thể bị quá tải. Trên thực tế, toán tử << được iostream sử dụng là toán tử có nhiều quá tải.

+0

Tôi cảm thấy không hài lòng với câu trả lời của bạn. Tại chỗ trên. –

2

Có, bạn có thể quá tải các nhà khai thác như thế này. Nhưng tôi không chắc chắn những gì "chuyển trường hợp" bạn đang đề cập đến. Bạn có thể sống với một tình trạng quá tải nếu bạn có một constructor chuyển đổi

class MyClass{ 
... 
// code for creating a MyClass out of an int 
MyClass(int n) { ... } 
... 
inline const MyClass MyClass::operator+(const MyClass &addend) const { 
    cout<<"Adding MyClass+MyClass"<<endl; 
    ...//Code for adding MyClass with MyClass 
} 
... 
}; 

Không chuyển đổi là cần thiết ở tất cả. Điều này đủ điều kiện nếu "MyClass" biểu diễn một cách hợp lý một số.

Lưu ý rằng bạn nên quá tải các toán tử này bởi các hàm không phải thành viên. Trong mã của bạn 5 + c1 sẽ không hoạt động, bởi vì không có toán tử nào lấy int như bên tay trái. Sau đây sẽ hoạt động

inline const MyClass operator+(const MyClass &lhs, const MyClass &rhs) { 
    // ... 
} 

Bây giờ nếu bạn giữ hàm tạo chuyển đổi, bạn có thể thêm int bằng một trong hai bên với chi phí mã tối thiểu.

+0

Johannes, trình chuyển đổi tiềm ẩn chuyển đổi có thể không phải là một ý tưởng hay. Đối với một, IME chuyển đổi tiềm ẩn thường trở thành một ý tưởng tồi sớm hay muộn, nhưng cũng bởi vì eladidan muốn làm điều này bởi vì "Tôi đang xây dựng một lớp mà tôi muốn được tối ưu nhất có thể." Trong trường hợp đó, tình trạng quá tải tốt hơn. – sbi

+1

Ồ, và không ngừng sao chép 'inline blah MyClass ::' vào 'MyClass' dường như không giống bạn chút nào. ':)' – sbi