Здравствуйте.
Снова обращаюсь с той же проблемой: перегрузкой операций. (Листинг прилагается)
Суть проблемы:
Есть класс — класс комплексных чисел (complex). В нем определены два public члена re и im.
Есть второй класс — класс полиномов (многочленов), который явл-ся потомком предыдущего класса. В этом классе есть две public переменные:
complex*p — массив коэффициентов многочлена.
int deg — степень многочлена.
При инициализации конструктор выделяет память под массив коэффициентов (р)
При деинициализации деструктор освобождает память из под (р) (delete [] p)
Пытаюсь определить операцию присваивания и сложения для полиномов. (см. листинг)
(Равенство степеней складываемых многочленов не проверяется, т.к. вопрос пока не в этом.Будем считать, что многочлены одинаковых степеней.)
Операции проходят, но почему то вызывается деструктор, причем четыре раза. Я конечно могу понять, что при выходе из операции + разрушается созданный там объект. Но почему разрушаются еще три объекта? Как это можно обойти? Перегружать операцию +=?
Операция выполняется в методе OnInitDialog() (диалоговое приложение mfc), вот так
polynom p1(2),p2(2),p3(2);
p3=p1+p2; здесь вызываются четыре деструктора.
Вопрос 2: можно ли определить операцию присваивания так, чтобы в левой части был указатель на объект(причем не инициализированный), а в самой операции происходило бы выделение памяти под объект (new) и возврашался бы указатель?
Т.е.
polynom p1(2),p2(2),*p3;
...
p1,p2 как-то заполнюятся значениями
...
p3=p1+p2 <- Как сделать так?
Заранее спасибо.
Обещанный листинг:
// complex.h: interface for the complex class.
//
//////////////////////////////////////////////////////////////////////
}
}
polynom polynom::operator=(polynom&a){
for (int i=0;i<=a.deg;i++) { this->p[i].im=a.p[i].im; this->p[i].re=a.p[i].re;
}
return*this;
}
polynom polynom::operator+(polynom a) {
polynom tmp(a.deg);
for (int i=0;i<=a.deg;i++) {
tmp.p[i].im=this->p[i].im+a.p[i].im;
tmp.p[i].re=this->p[i].re+a.p[i].re;
}
return tmp; // вот здесь tmp должен разрушиться. Что вообщем то и происходит.
}
//
BOOL CExDlg::OnInitDialog()
{
// все лишнее удалено
polynom a(2),b(2),c(2);
// c=a;
c=a+b;
return TRUE; // return TRUE unless you set the focus to a control
}
"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>polynom polynom::operator=(const polynom&); АТ>polynom polynom::operator+(const polynom&);
Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
Здравствуйте Андрей Тарасевич, Вы писали:
АТ>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>>polynom polynom::operator=(const polynom&); АТ>>polynom polynom::operator+(const polynom&);
АТ>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
АТ>polynom polynom::operator=(const polynom&); АТ>polynom polynom::operator+(const polynom&) const;
И не создавать временный объект, что-ли, т.е. писать this->.... = this-> ... + что-то
return*this
Так?
А как быть со вторым вопросом?
polynom a(2),b(2),*c
c=a*b — это можно сделать и как?
Re[4]: Перегрузка операций (дубль два с исходниками)
Здравствуйте Гарин Георгий, Вы писали:
ГГ>Здравствуйте Андрей Тарасевич, Вы писали:
АТ>>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>>>polynom polynom::operator=(const polynom&); АТ>>>polynom polynom::operator+(const polynom&);
АТ>>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
АТ>>polynom polynom::operator=(const polynom&); АТ>>polynom polynom::operator+(const polynom&) const; ГГ> И не создавать временный объект, что-ли, т.е. писать this->.... = this-> ... + что-то ГГ> return*this ГГ> Так?
Не так. Временный объект тебе создавать придется — ты же где-то должен получить результат, а this изменять не верно, т.к. это operator +, а не operator += (да и как тут было справедливо замечено его правильно было бы объявить как const).
ГГ> А как быть со вторым вопросом? ГГ> polynom a(2),b(2),*c ГГ> c=a*b — это можно сделать и как?
Можно.
[code]
polinom* polinom::operator*(const polinom&) const
{
polinom* res = new polinom;
...
какой-то код
...
return res;
}
[\code]
Только на мой взляд не нужно (но это из серии "О вкусах не спорят").
Да, а чего я действительно не понял, так это зачем класс polinom делать наследником класса copmlex? Он по-моему к нему никаких родственных отношений не имеет.
И еще одна мелочь: деструктор класса наследника необязательно объявлять virtual, если он объявлен в базовом классе как virtual. Не лениво лишний раз по клавишат бить?
Re[3]: Перегрузка операций (дубль два с исходниками)
Здравствуйте Андрей Тарасевич, Вы писали:
АТ>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>>polynom polynom::operator=(const polynom&); АТ>>polynom polynom::operator+(const polynom&);
АТ>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
АТ>polynom polynom::operator=(const polynom&); АТ>polynom polynom::operator+(const polynom&) const;
И еще одно уточнеие в операторе '=' следует возвращать ссылку на текущий объект:
polynom& polynom::operator=(const polynom&);
и избавемся от еще одного временного объекта.
Кто ищет то всегда найдет!
Re[5]: Перегрузка операций (дубль два с исходниками)
Здравствуйте grs, Вы писали:
grs>Здравствуйте Гарин Георгий, Вы писали:
ГГ>> А как быть со вторым вопросом? ГГ>> polynom a(2),b(2),*c ГГ>> c=a*b — это можно сделать и как? grs>Можно. grs>[code] grs>polinom* polinom::operator*(const polinom&) const grs>{ grs> polinom* res = new polinom; grs> ... grs> какой-то код grs> ... grs> return res; grs>} grs>[\code] grs>Только на мой взляд не нужно (но это из серии "О вкусах не спорят").
Просто это очень упрощенный пример того, что я пишу. На самом деле у меня класс многочленов в поле Галуа и перегружены операции / * % (деление,умножение и остаток)
И хотелось бы, чтобы например при умножении результирующий полином создавался автоматически, т.е. его степень была бы равна сумме степеней сомножителей.
grs>Да, а чего я действительно не понял, так это зачем класс polinom делать наследником класса copmlex? Он по-моему к нему никаких родственных отношений не имеет.
см выше grs>И еще одна мелочь: деструктор класса наследника необязательно объявлять virtual, если он объявлен в базовом классе как virtual. Не лениво лишний раз по клавишат бить?
Так я и не бью. Это vc сам написал.
Спасибо за ответ.
Re[3]: Перегрузка операций (дубль два с исходниками)
Здравствуйте Андрей Тарасевич, Вы писали:
АТ>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
АТ>polynom polynom::operator+(const polynom&) const;
А вот и нет operator +() const должен быть объявлен как const как-раз потому, что он не изменяет состояния экземпляра, которому он принадлежит, а не который — левый операнд.
Пример:
class test
{
public:
...
inline void ConstFunc( test& r ) const { r.n = <целое число>; }
...
private:
int n;
};
Так-что, как раз неизменность аргумента для этого случая не важна, хотя, раз он тоже не изменяется внутри метода-оператора, его тоже стоит определять с модификатором const.
С уважением.
Алексей Кирдин
Re[4]: Перегрузка операций (дубль два с исходниками)
Отвечу себе-же А вот и да! Как-то расслабился. Все правильно: объект и есть левый операнд оператора )
Короче, повтоорил все то же другими словами. Сорри.
Алексей Кирдин
Re[4]: Перегрузка операций (дубль два с исходниками)
Здравствуйте Гарин Георгий, Вы писали:
АТ>>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:
АТ>>>polynom polynom::operator=(const polynom&); АТ>>>polynom polynom::operator+(const polynom&);
АТ>>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:
АТ>>polynom polynom::operator=(const polynom&); АТ>>polynom polynom::operator+(const polynom&) const; ГГ> И не создавать временный объект, что-ли, т.е. писать this->.... = this-> ... + что-то ГГ> return*this ГГ> Так?
Нет. Для возвращаемого значения временный объект все-таки создать придется. От этого никуда не денешься. А вот копировать параметры незачем. Т.е. тело твого оператора '+' пусть останется как есть. Подправить надо только объявление параметров.
ГГ> А как быть со вторым вопросом? ГГ> polynom a(2),b(2),*c ГГ> c=a*b — это можно сделать и как?
Да сделать-то несложно. Как ты сам написал, так и делай. В реализации оператора '+' выделяй новый объект череp new и возвращай указатель на него. Но криво это. Ничего хорошего, на мой взгляд, из этого не выйдет.
Best regards,
Андрей Тарасевич
Re[4]: Перегрузка операций (дубль два с исходниками)
Здравствуйте IAZ, Вы писали:
IAZ>И еще одно уточнеие в операторе '=' следует возвращать ссылку на текущий объект:
IAZ>polynom& polynom::operator=(const polynom&);
IAZ>и избавемся от еще одного временного объекта.