2013-03-15 58 views
15

Tôi đang học C++ và tôi đã tạo hai ứng dụng chào đơn giản trên thế giới. Trong cả hai, tôi sử dụng quá tải của nhà điều hành, nhưng đây là vấn đề. Trên cái đầu tiên, tôi có thể cung cấp hai đối số cho toán tử quá tải, và nó ổn.Số lượng đối số trong quá tải toán tử trong C++

Tiêu đề:

enum Element {a,b,c,d,e}; 
Element operator + (Element x, Element y); 
//more overloads for -, *,/here 

Nguồn:

Element operator + (Element x, Element y) { 
    return ArrayOfElements[x][y]; 
} 

Nhưng trong ứng dụng thứ hai của tôi (đơn giản số phức tạp tính) - Phương pháp này không làm việc. Sau khi googling và tìm ra lý do tại sao, tôi kết thúc với mã này:

Tiêu đề:

struct Complex { 
     double Re; 
     double Im; 

     Complex (double R, double I) : Re(R), Im(I) { } 

     Complex operator + (Complex &Number); 
     //more overloads 
    }; 

Nguồn:

Complex Complex::operator + (Complex &Number) 
    { 
     Complex tmp = Complex(0, 0); 
     tmp.Re = Re + Number.Re; 
     tmp.Im = Im + Number.Im; 
     return tmp; 
    } 

Đó là làm việc bây giờ, nhưng tôi muốn biết , tại sao trong đoạn mã đầu tiên tôi được phép đặt hai đối số trong quá trình nạp chồng operator, nhưng với lần thứ hai tôi đã bị lỗi sau?

complex.cpp:5:51: error: 'Complex Complex::operator+(Complex, Complex)' must take either zero or one argument 

Cũng giống như bất cứ khi nào tôi sử dụng lớp học hay không. Tôi đã tìm kiếm qua nhiều tài liệu và cách thứ hai dường như chính xác hơn. Có lẽ đó là vì các loại đối số khác nhau?

Cả hai nguồn được biên dịch với thông số -Wall -pedantic sử dụng g++, cả hai đều đang sử dụng cùng một thư viện.

+5

Các hàm thành viên có tiềm ẩn 'this' luận –

Trả lời

24

Giả sử bạn có một lớp học như thế này:

class Element { 
public: 
    Element(int value) : value(value) {} 
    int getValue() const { return value; } 
private: 
    int value; 
}; 

Có bốn cách để xác định một nhà điều hành nhị phân như +.

  1. Là một chức năng miễn phí với quyền truy cập vào chỉ public thành viên của lớp:

    // Left operand is 'a'; right is 'b'. 
    Element operator+(const Element& a, const Element& b) { 
        return Element(a.getValue() + b.getValue()); 
    } 
    

    e1 + e2 == operator+(e1, e2)

  2. Như một hàm thành viên, với quyền truy cập vào tất cả các thành viên của lớp:

    class Element { 
    public: 
        // Left operand is 'this'; right is 'other'. 
        Element operator+(const Element& other) const { 
         return Element(value + other.value); 
        } 
        // ... 
    }; 
    

    e1 + e2 == e1.operator+(e2)

  3. Là một chức năng friend, với quyền truy cập vào tất cả các thành viên của lớp:

    class Element { 
    public: 
        // Left operand is 'a'; right is 'b'. 
        friend Element operator+(const Element& a, const Element& b) { 
         return a.value + b.value; 
        } 
        // ... 
    }; 
    

    e1 + e2 == operator+(e1, e2)

  4. Là một chức năng friend định nghĩa bên ngoài lớp cơ thể giống hệt nhau trong hành vi để # 3:

    class Element { 
    public: 
        friend Element operator+(const Element&, const Element&); 
        // ... 
    }; 
    
    Element operator+(const Element& a, const Element& b) { 
        return a.value + b.value; 
    } 
    

    e1 + e2 == operator+(e1, e2)

+3

Nếu đó là một hàm thành viên, bạn có thể làm 'Element (2) + 3' nhưng không '2 + Yếu tố (3)'. – aschepler

+0

tôi không có bất kỳ lớp học trong một đầu tiên (chỉ trong một giây), nhưng nhờ cho câu trả lời tuyệt vời! – Lemurr

1

Nếu bạn thích rằng operator+ mất cả hai toán hạng như các đối số rõ ràng, nó phải được định nghĩa là một miễn phí (tức là phi thành viên) chức năng:

class Complex { 
    friend Complex operator+(const Complex& lhs, const Complex& rhs); 
} 

Complex operator+(const Complex& lhs, const Complex& rhs) { 
    ... 
} 

Bạn sử dụng hình thức này nếu toán hạng bên trái là một kiểu nguyên thủy, hoặc của một lớp mà bạn không kiểm soát (và do đó không thể thêm một hàm thành viên vào).

+2

... và bạn nên sử dụng hình thức này nếu có thể có bất kỳ chuyển đổi ngầm cho 'Complex'. – aschepler

4

Vì + là toán tử nhị phân, nếu bạn quá tải bên trong cấu trúc/lớp, bạn chỉ có thể cung cấp thêm một toán hạng, lý do là toán hạng đầu tiên ngầm là đối tượng gọi. Đó là lý do tại sao trong trường hợp đầu tiên, bạn có hai tham số vì nó nằm ngoài phạm vi của lớp/struct của bạn, trong khi trong trường hợp thứ hai, nó đã bị quá tải làm hàm thành viên.

1

Nếu chức năng quá tải là một hàm thành viên của lớp, chúng tôi vượt qua chỉ có một đối số, và có một tham số ẩn ( con trỏ này) trỏ đến đối tượng khác cần thiết để thực hiện thao tác nhị phân như '+ '. này trỏ trỏ đến một trong các toán hạng và gọi hàm bị quá tải; trong khi toán hạng khác được chuyển làm đối số. Ví dụ:

class ExampleClass 
{ 
public: 
    int x; 
    //a this pointer will be passed to this function 
    ExampleClass& operator+(const ExampleClass& o){ return x+o.x; } 
}; 



ExampleClass obj1, obj2, obj; 
obj = obj1 + obj2; //the overloaded function is called as obj1.operator+(obj2) internally 
        //this pointer is passed to the function 

Khi chức năng quá tải không phải là một hàm thành viên (hoặc một chức năng miễn phí hoặc một hàm friend), sau đó chúng tôi không có con trỏ này cung cấp cho các chức năng quá tải. Trong trường hợp này, trình biên dịch mong đợi hai đối số cho hàm được sử dụng làm toán hạng.

class ExampleClass 
{ 
    public: 
     int x; 
     //this pointer will not be passed to this function 
     friend ExampleClass& operator+(const ExampleClass& o1, const ExampleClass& o2){ return o1.x+o2.x; } 
}; 



obj = obj1 + obj2; //the overloaded function is called as operator+(obj1, obj2) internally 
0

e1 + e2 == e1.operator + (e2) điều này có nghĩa e1 là một đối tượng và điều hành + là thành viên và e2 là như là một biến .basicaly oops cho phép chúng ta làm chỉ cần viết e1 + e2 trình biên dịch tự động hiểu như một e1.operator + (e1)