Open Dashia18 opened 9 years ago
Совершенно правильно говоришь, перегруженный оператор - то просто метод класса. Ты его даже вызвать можешь как метод:
sf_a.operator+(sf_b)
Но поскольку ты перегружаешь оператор то твой метод должен отвечать требованиям этого оператора. В случае operator+, требование - принимать ровно два аргумента. Но мы знаем что у метода класса есть всегда неявный аргумент - указатель на объект этого класса. Поэтому в объявлении перегруженного оператора мы пишем только один аргумент.
Ещё можно перегрузить оператор вывода в поток и тогда можно писать код типа
Simple_fraction a, b;
std::cout << a << " " << b <<std::endl;
Почему не работает с оператором вывода - вспоминаем ещё раз как устроены функции-члены класса. У метода класса есть всегда неявный аргумент - указатель на объект этого класса. Поэтому если мы написали
class Simple_fraction{
...
std::ostream& operator<<(const Simple_fraction& f)
{
...
}
}
то работать не будет, ведь с точки зрения компилятора мы объявили функцию, которая принимает два объекта типа Simple_fraction и возвращает объект потока вывода. А пытаемся вызвать её, передавая объект потока вывода и объект типа Simple_fraction. Выход:
А почему вызовы функций в таком виде?
sf_a.Simple_fraction::get_numerator()
Ну можно без пространства имен писать:
Simple_fraction::
sf_a.get_numerator()
В этом что-то не так?
Перегруженный оператор вывода. operator<< Объявление:
friend std::ostream& operator<< (std::ostream& out, const Simple_fraction& sf_a);
Реализация:
std::ostream& operator<< (std::ostream& out, const Simple_fraction& sf_a){
out<<"(operator >> overloading) SF = "<<sf_a.get_numerator()<<"/"<<sf_a.get_denominatior()<<"\n\n";
return out;
}
Вызов:
std::cout<<sf_a;
Для чего же здесь использовать дружественную функцию?
Так как у методов класса первый неявный параметр это указатель на объект, а оператор вывода слева должен принимать логический поток, а не параметр для печати, поэтому используют дружественную функцию, которая явно принимает левый и правый операнд. И по сути это метод (функция), которая не применяется к объекту, а вызывается как обычная функция, принимает нужные параметры но объявлена в классе.
А еще дружественная функция имеет доступ к скрытым и защищенным полям класса, и может быть вызвана где угодно даже если она объявлена после ключевого слова privat. Так же этот метод - не член этого класса и может вызываться несколькими классами. (все что я узнала про дружественные функции и приняла:) )
P.S. Вообще сложно понять для чего нужна та или иная новая штукенция. В общем так?
Благодаря тому, что ты сделала геттеры для полей numerator и denomenator тебе не нужна дружественная функция. Попробуй убрать эти два метода - и сразу окажется что функция должна быть дружественной, иначе доступ к ним никак не получить. Вообще говоря, дружественность - это некоторый хак в языке, и с точки зрения "правильного ООП"(ТМ) нужно объявлять геттеры и получать значения полей через них, что ты и сделала. Однако, если нужно особое быстродействие (и если подтверждено что тормозит именно это место), можно избежать лишнего вызова метода и просто сделать функцию другом. Ну и да, если полей много и нужен ко всем доступ (функция всё та же самая - распечатываем содержимое объекта, так называемая сериализация), то писать на каждое поле геттер долго и нудно, проще объявить друга.
Ты так сложно написал, честно... Дружественная функция не член класса, поэтому доступ к полям классам у нее все равно через get-методы. Поэтому я не понимаю про что ты пишешь, что get-методы можно убрать.
Да если сделать эту функцию вне класса, и также через get-методы, то все так же будет работать. Но я хотела сделать что бы она была в классе.
Прости что сложно... Если функция объявлена как друг, то она может обращаться к приватным полям и методам класса напрямую. Компилятору не важно, напишешь ты реализацию дружественной функции в классе или вне него - она всё равно не будет членом класса, но сохранит доступ к его приватным полям и методам. Так что где писать реализацию - твой личный выбор, нравится больше в классе - значит будет в классе)
Нет, строчка в коде где метод обращается к полям класса не будет работать без get-методов.
//operator overloading print << Simple_fraction
std::ostream& operator<< (std::ostream& out, const Simple_fraction& sf_a){
out<<"(operator >> overloading) SF = "<<sf_a.get_numerator()<<"/"<<sf_a.get_denominatior()<<"\n\n";
return out;
}
Вот так работает здесь можно запустить:
#include <iostream>
class Simple_fraction{
public:
Simple_fraction(int num, int den)
: numerator(num)
, denominatior(den)
{}
friend std::ostream& operator<< (std::ostream& out, const Simple_fraction& sf_a)
{
out << sf_a.numerator << '/' << sf_a.denominatior;
return out;
}
private:
int numerator;
int denominatior;
};
int main() {
Simple_fraction s(1,2);
std::cout << s << std::endl;
return 0;
}
Перегрузка операторов //объявление Simple_fraction operator+ (const Simple_fraction& sf_b); //реализация Simple_fraction Simple_fraction::operator+ (const Simple_fraction& sf_b){ ...
int n1 = numerator; int d1 = denominatior; int n2 = sf_b.get_numerator(); int d2 = sf_b.get_denominatior(); ... }
//вызов sf_a + sf_b;
Перегрузка сродни методу класса и применяется к левому операнду? sf_a.operator+(sf_b) Почему ругается что слишком много переменных если записать: //объявление Simple_fraction operator+ (const Simple_fraction& sf_a, const Simple_fraction& sf_b);