Majid Azimi
Majid Azimi

Reputation: 5745

Operator overloading: calling friend function from member function

I have a Student class. I want to overload + operator so I can add a double variable to class. Here is Student class:

class Student {
private:
    std::string firstName;
    double grade;
public:
    Student(const std::string &firstName, double grade);

    double getGrade() const;

    friend Student operator+(double grade, const Student &student);

    Student operator+(double grade) const;
}; 

And implementation:

Student::Student(const std::string &firstName, double grade) {
    this->firstName = firstName;
    this->grade = grade;
}

double Student::getGrade() const {
    return grade;
}

Student operator+(double grade, const Student &student) {
    return Student(student.firstName, student.grade + grade);
}

Student Student::operator+(double grade) const {
    return operator+(grade, *this);
}

double + Student is done via friend function and Student + double goes through member function. When I compile I get this:

error: no matching function for call to ‘Student::operator+(double&, const Student&) const’
     return operator+(grade, *this);
                                  ^
note: candidate is:
note: Student Student::operator+(double) const
 Student Student::operator+(double grade) const {
         ^
note:   candidate expects 1 argument, 2 provided

Why I can't call a friend function from a member function?

[UPDATE]

However when I overload << operator, I can call it from member function without pre-pending ::.

friend std::ostream &operator<<(std::ostream &os, const Student &student);

and the implementation:

std::ostream &operator<<(std::ostream &os, const Student &student) {
    os << student.grade;
    return os;
}

Upvotes: 2

Views: 1127

Answers (1)

Marco A.
Marco A.

Reputation: 43662

You're trying to call the member function, not the friend function (cfr. C++11 7.3.1.2/3). You should rather write

Student Student::operator+(double grade) const {
    return ::operator+(grade, *this);
}

Example

Using the :: makes sure overload resolution occurs from the global namespace you're currently in.

Another way (less readable in my opinion) is to add the friend function to the overload resolution set

Student Student::operator+(double grade) const {
    using ::operator+;
    return operator+(grade, *this);
}

or, more readable, as Jarod suggested,

Student Student::operator+(double grade) const {
    return grade + *this;
}

Edit: as for the "why": [class.friend]/p7 and [basic.lookup.argdep]/p3 explain that a member function with the same name "hides" during overload resolution the name of the friend function.

Upvotes: 3

Related Questions