Как работает функция друзей - PullRequest
1 голос
/ 28 января 2020

Я хотел бы узнать, как использовать друг функции. Когда я пытаюсь сделать это впервые, у меня возникает небольшая проблема, и я не знаю, как это исправить. Я получил следующие ошибки:

|17|error: 'minutes' was not declared in this scope|
|18|error: 'hours' was not declared in this scope|
|24|error: 'minutes' was not declared in this scope|
|24|error: 'minutes' was not declared in this scope|

Вот весь код, который у меня есть на данный момент:

#include <iostream>
using namespace std;

class Time
{

    int hours;
    int minutes;
    friend Time operator+(const Time & t);
    friend void x(Time h, Time m );

};

Time operator+(const Time & t)
{
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}


void x(Time h, Time m) {hours = h; minutes = m;}

Ответы [ 3 ]

1 голос
/ 28 января 2020

Эти сообщения об ошибках

| 17 | error: 'minutes' не было объявлено в этой области |

| 18 | ошибка: «часы» не были объявлены в этой области |

означает, что в этом определении функции

Time operator+(const Time & t)
{
    Time sum;
    sum.minutes = minutes + t.minutes;
                  ^^^^^^^
    sum.hours = hours + t.hours + sum.minutes / 60;
                ^^^^^
    sum.minutes %= 60;
    return sum;
}

переменные minutes и hours не объявлены. Функция не является функцией-членом класса. Таким образом, эти переменные не являются членами данных объекта класса Time. Они являются необъявленными идентификаторами.

Функции-друзья не получают неявный аргумент this, как это делают нестатические c функции класса-члена.

Эти сообщения об ошибках

| 24 | ошибка: «минуты» не были объявлены в этой области |

| 24 | ошибка: «минуты» не были объявлены в этой области |

имеют то же самое смысл. Функция x не является функцией-членом класса Time.

Если функция друга operator + перегружает двоичный оператор +, то она должна иметь два параметра.

Что касается второй функции-друга, то, похоже, ее задача состоит в том, чтобы установить значения для объекта типа Time.

Функции-друзья должны быть объявлены и определены следующим образом: показано в демонстрационной программе ниже.

#include <iostream>
#include <iomanip>

class Time
{
    int hours;
    int minutes;
    friend Time operator +( const Time &t1, const Time &t2 );
    friend void x( Time &t, int h, int m );
    friend std::ostream & operator <<( std::ostream &is, const Time &t );
};

Time operator +( const Time &t1, const Time &t2 )
{
    const int HOURS_IN_DAY = 24;
    const int MINUTES_IN_HOUR = 60;

    Time t;

    t.hours  = t1.hours + t2.hours + ( t1.minutes + t2.minutes ) / MINUTES_IN_HOUR;
    t.hours %= HOURS_IN_DAY;
    t.minutes = ( t1.minutes + t2.minutes ) % MINUTES_IN_HOUR;

    return t;
}

void x( Time &t, int h, int m )
{
    t.hours = h;
    t.minutes = m;
}

std::ostream & operator <<( std::ostream &os, const Time &t )
{
    return 
    os << std::setw( 2 ) << std::setfill( '0' ) << t.hours 
       << ':'
       << std::setw( 2 ) << std::setfill( '0' ) << t.minutes; 
}

int main() 
{
    Time t1;

    x( t1, 16, 10 );

    std::cout << t1 << '\n';

    Time t2;

    x( t2, 10, 20 );

    std::cout << t2 << '\n';

    std::cout << t1 + t2 << '\n';

    return 0;
}

Вывод программы:

16:10
10:20
02:30
1 голос
/ 28 января 2020

friend функции / классы - это функции / классы, которые могут получить доступ к private и protected членам.

Функция друга не является функцией-членом класса, для которого она объявлена ​​другом, поэтому она не не имеет неявного указателя this, поэтому в:

void x(Time h, Time m) {hours = h; minutes = m;} // doesn't compile

Поскольку до тех пор, пока hours и minutes являются членами данных объекта типа класса Time, вам необходимо получить к ним доступ через объект этого класса.

  • позвольте 'предположить, что ваш класс Time имеет функцию-член с именем setMinutes(), которая определяется как:

    int Times::SetMinutes(int h, int m)
    {
           hours = h; // in fact it is translated as: this->hours = h;
           this->minutes = m;
    }
    
  • Как вы уже могли видеть, оператор вставки << перегружается классом следующим образом:

    friend std:ostream& operator<<(std::ostream& out, const Time& rhs) // friend here is only to access private and protected members
    {
            out << rhs.hours << " " << rhs.minutes; // not out << hours << minutes;   * if the keyword `friend` is removed then this line will not compile: "accessing private members".
            return out;
    } 
    
  • Также объявление оператора + неверно:

    friend Time operator+(const Time & t);
    

Поскольку + является двоичным оператором, ему нужны два операнда "lhs" и "rhs", поэтому вы можете:

     friend Time operator+(const Time & lsh, const Time& rhs);

Или:

     Time operator+(const Time & t); // OK
  • Вторая версия работает, потому что + является функцией-членом: это означает, что она использует объект, на котором оператор вызывается как "lhs" посредством разыменования this и аргумента t как "rhs".

  • Предпочтительной версией является friend one.

1 голос
/ 28 января 2020

Когда вы пишете:

class Time
{
    friend Time operator+(const Time & t);
};

Тогда operator+ не является функцией-членом. Это свободная функция, и строка в объявлении класса только объявляет, что эта функция является другом класса Time.

. В качестве нечленов двоичный файл operator+ должен принимать 2 параметра. Подумайте, как бы вы его использовали:

Time a,b;
Time c = a + b;

Вам нужно передать a и b и вернуть новое Time c:

Time operator+(const Time & t1,const Time& t2)
{
    Time sum;
    sum.minutes = t1.minutes + t2.minutes;
    sum.hours = t1.hours + t2.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

У вас есть похожие проблема с x, но я не понимаю, что он должен делать. Если вы понимаете проблему с operator+, вы также сможете исправить это.

...