2010-05-13 41 views
18

Trong một dự án tôi đang làm việc, tôi có một lớp học Score, được định nghĩa bên dưới trong score.h. Tôi đang cố gắng để quá tải nó như vậy, khi một hoạt động << được thực hiện trên nó, _points + " " + _name được in.các chức năng 'người bạn' và << quá tải toán tử: Cách thích hợp để quá tải một toán tử cho một lớp là gì?

Đây là những gì tôi đã cố gắng để làm:

ostream & Score::operator<< (ostream & os, Score right) 
{ 
    os << right.getPoints() << " " << right.scoreGetName(); 
    return os; 
} 

Dưới đây là các lỗi trả về:

score.h(30) : error C2804: binary 'operator <<' has too many parameters 

(Lỗi này xuất hiện 4 lần, trên thực tế)

tôi quản lý để làm cho nó làm việc bằng cách tuyên bố tình trạng quá tải là chức năng của bạn bè:

friend ostream & operator<< (ostream & os, Score right); 

Và xóa Score:: khỏi khai báo hàm trong score.cpp (có hiệu quả không khai báo nó làm thành viên).

Tại sao tính năng này hoạt động, nhưng đoạn mã cũ không?

Cảm ơn bạn đã dành thời gian!

EDIT

Tôi đã xóa tất cả đề cập đến tình trạng quá tải về các tập tin tiêu đề ... nhưng tôi nhận được (chỉ và) lỗi sau. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) Làm thế nào để kiểm tra của tôi, trong chính(), không thể tìm thấy tình trạng quá tải thích hợp? (Nó không bao gồm, tôi đã kiểm tra)

Dưới đây là toàn bộ score.h

#ifndef SCORE_H_ 
#define SCORE_H_ 

#include <string> 
#include <iostream> 
#include <iostream> 

using std::string; 
using std::ostream; 

class Score 
{ 

public: 
    Score(string name); 
    Score(); 
    virtual ~Score(); 
    void addPoints(int n); 
    string scoreGetName() const; 
    int getPoints() const; 
    void scoreSetName(string name); 
    bool operator>(const Score right) const; 

private: 
    string _name; 
    int _points; 

}; 
#endif 

Trả lời

54

Lưu ý: Bạn có thể muốn nhìn vào operator overloading FAQ.


Toán tử nhị phân có thể là thành viên của lớp đối số bên trái hoặc chức năng miễn phí của chúng. (Một số toán tử, như gán, phải là thành viên.) Vì đối số bên trái của toán tử luồng là luồng, nên các toán tử luồng phải là thành viên của lớp luồng hoặc các hàm miễn phí. Cách kinh điển để thực hiện operator<< cho bất kỳ loại là thế này:

std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    // stream obj's data into os 
    return os; 
} 

Lưu ý rằng nó là không một hàm thành viên. Cũng lưu ý rằng phải mất đối tượng để truyền theo tham chiếu const. Đó là bởi vì bạn không muốn sao chép các đối tượng để dòng nó và bạn không muốn streaming để thay đổi nó.


Đôi khi bạn muốn truyền các đối tượng không thể truy cập vào nội bộ thông qua giao diện công khai của lớp học, vì vậy nhà điều hành không thể truy cập chúng.Sau đó, bạn có hai lựa chọn: Hoặc là đặt một thành viên nào vào lớp mà không streaming

class T { 
    public: 
    void stream_to(std::ostream&) const {os << obj.data_;} 
    private: 
    int data_; 
}; 

và gọi đó là từ các nhà điều hành:

inline std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    obj.stream_to(os); 
    return os; 
} 

hoặc làm cho các nhà điều hành một friend

class T { 
    public: 
    friend std::ostream& operator<<(std::ostream&, const T&); 
    private: 
    int data_; 
}; 

để có thể truy cập các phần riêng tư của lớp học:

inline std::ostream& operator<<(std::ostream& os, const T& obj) 
{ 
    os << obj.data_; 
    return os; 
} 
+0

Nice, câu trả lời hoàn chỉnh. –

+0

Truy cập phần riêng tư của lớp học - Rawr. J/K, cảm ơn bạn rất nhiều, nhưng vẫn còn một câu hỏi: Tôi đã xóa tất cả các đề cập đến quá tải trên tệp tiêu đề ... nhưng tôi nhận được lỗi sau (và chỉ). 'nhị phân' << ': không tìm thấy toán tử nào có toán hạng bên phải của loại' Điểm '(hoặc không có chuyển đổi được chấp nhận)' Làm thế nào để thử nghiệm của tôi, trong chính(), không thể tìm thấy quá tải? (nó không phải là bao gồm). –

+1

Bạn nên đặt khai báo 'toán tử <<' ngay với định nghĩa lớp của bạn: đó là trong cùng một tiêu đề và trong cùng một không gian tên. Bằng cách này bạn sẽ không quên bao gồm nó và bạn trình biên dịch sẽ có thể nhặt nó lên khi tìm kiếm quá tải chấp nhận được. –

9

Hãy nói rằng bạn muốn viết một tình trạng quá tải nhà điều hành cho +, do đó bạn có thể thêm hai Score đối tượng với nhau, và một người khác, do đó bạn có thể thêm một int đến một Score, và một phần ba, do đó bạn có thể thêm một Score một int . Những người có số Score là tham số đầu tiên có thể là hàm thành viên của Điểm. Nhưng một trong đó int là thông số đầu tiên không thể trở thành chức năng thành viên của int, phải không? Để giúp bạn với điều đó, bạn được phép viết chúng như là các chức năng miễn phí. Đó là những gì đang xảy ra với nhà điều hành << này, bạn không thể thêm chức năng thành viên vào ostream để bạn viết một chức năng miễn phí. Đó là ý nghĩa của nó khi bạn lấy đi phần Score::.

Bây giờ tại sao nó phải là friend? Nó không. Bạn chỉ đang gọi các phương thức công khai (getPointsscoreGetName). Bạn thấy rất nhiều người điều hành bởi vì họ muốn nói chuyện trực tiếp với các biến riêng tư. Tôi không thể làm điều đó, bởi vì chúng được viết và duy trì bởi người duy trì lớp. Chỉ cần không nhận được phần bạn bè lộn xộn với phần thành viên-chức năng-vs-miễn phí-chức năng.

+0

Cảm ơn bạn đã thêm đầu vào! –

6

Bạn đang gặp phải lỗi biên dịch khi operator<< là hàm thành viên trong ví dụ vì bạn đang tạo một operator<< có tham số Score làm đối tượng đầu tiên (đối tượng được gọi) và sau đó thêm tham số ở cuối.

Khi bạn gọi một toán tử nhị phân được khai báo là hàm thành viên, bên trái của biểu thức là đối tượng mà phương thức đang được gọi. ví dụ. a + b sức làm việc như thế này:

A a; 
B b 

a.operator+(b) 

Nó thường thích hợp hơn để sử dụng các toán nhị phân phi thành viên (và trong một số trường hợp - ví dụ operator<< cho ostream là cách duy nhất để làm điều đó Trong trường hợp đó, a + b có thể làm việc như thế nào. này:

A a; 
B b 

operator+(a, b); 

Dưới đây là một ví dụ đầy đủ cho thấy cả hai cách để làm việc đó; main() sẽ ra '55' ba lần:

#include <iostream> 

struct B 
{ 
    B(int b) : value(b) {} 
    int value; 
}; 


struct A 
{ 
    A(int a) : value(a) {} 
    int value; 

    int operator+(const B& b) 
    { 
     return this->value + b.value; 
    } 
}; 

int operator+(const A& a, const B& b) 
{ 
    return a.value + b.value; 
} 

int main(int argc, char** argv) 
{ 
    A a(22); 
    B b(33); 

    std::cout << a + b << std::endl; 
    std::cout << operator+(a, b) << std::endl; 
    std::cout << a.operator+(b) << std::endl; 

    return 0; 
} 
Các vấn đề liên quan