Re[3]: Перегрузка операций (дубль два с исходниками)
От: IAZ http://iaz.simb.ru
Дата: 25.01.02 09:12
Оценка: 15 (2)
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:


АТ>>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[2]: Перегрузка операций (дубль два с исходниками)
От: Андрей Тарасевич Беларусь  
Дата: 25.01.02 08:02
Оценка: 2 (1)
АТ>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:

АТ>polynom polynom::operator=(const polynom&);

АТ>polynom polynom::operator+(const polynom&);

Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:

polynom polynom::operator=(const polynom&);
polynom polynom::operator+(const polynom&) const;
Best regards,
Андрей Тарасевич
Перегрузка операций (дубль два с исходниками)
От: Гарин Георгий  
Дата: 25.01.02 07:52
Оценка:
Здравствуйте.
Снова обращаюсь с той же проблемой: перегрузкой операций. (Листинг прилагается)
Суть проблемы:
Есть класс — класс комплексных чисел (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.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_COMPLEX_H__5100A56F_1124_11D6_90B7_B70084C92051__INCLUDED_)
#define AFX_COMPLEX_H__5100A56F_1124_11D6_90B7_B70084C92051__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class complex
{
public:
double re,im;
complex();
virtual ~complex();

};

#endif // !defined(AFX_COMPLEX_H__5100A56F_1124_11D6_90B7_B70084C92051__INCLUDED_)




// complex.cpp: implementation of the complex class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ex.h"
#include "complex.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

complex::complex()
{

}

complex::~complex()
{

}


// polynom1.h: interface for the polynom class.
//
//////////////////////////////////////////////////////////////////////
#include "complex.h"
#if !defined(AFX_POLYNOM1_H__5100A571_1124_11D6_90B7_B70084C92051__INCLUDED_)
#define AFX_POLYNOM1_H__5100A571_1124_11D6_90B7_B70084C92051__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000



class polynom : public complex
{
public:

complex* p;

polynom(int);
virtual ~polynom();
polynom polynom::operator=(polynom&);
polynom polynom::operator+(polynom);
int deg;
};

#endif // !defined(AFX_POLYNOM1_H__5100A571_1124_11D6_90B7_B70084C92051__INCLUDED_)



// polynom1.cpp: implementation of the polynom class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "ex.h"
#include "polynom1.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

polynom::polynom(int degree)
{
try {
deg=degree;
p=new complex[degree+1];
if (!p) throw "constructor error";
}
catch (char*msg){
::MessageBox(NULL,msg,NULL,MB_OK);
}

}
polynom::~polynom(){
try {
delete [] p;
}
catch(...) {
::MessageBox(NULL,"destructor error",NULL,MB_OK);







}
}
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
}
Re: Перегрузка операций (дубль два с исходниками)
От: Андрей Тарасевич Беларусь  
Дата: 25.01.02 08:00
Оценка:
Здравствуйте Гарин Георгий, Вы писали:


ГГ>class polynom : public complex

ГГ>{
ГГ>public:

ГГ> complex* p;

ГГ>
ГГ> polynom(int);
ГГ> virtual ~polynom();
ГГ> polynom polynom::operator=(polynom&);
ГГ> polynom polynom::operator+(polynom);
ГГ> int deg;
ГГ>};

"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:

polynom polynom::operator=(const polynom&);
polynom polynom::operator+(const polynom&);
Best regards,
Андрей Тарасевич
Re[3]: Перегрузка операций (дубль два с исходниками)
От: Гарин Георгий  
Дата: 25.01.02 08:13
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:


АТ>>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]: Перегрузка операций (дубль два с исходниками)
От: grs Россия  
Дата: 25.01.02 08:56
Оценка:
Здравствуйте Гарин Георгий, Вы писали:

ГГ>Здравствуйте Андрей Тарасевич, Вы писали:


АТ>>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:


АТ>>>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[5]: Перегрузка операций (дубль два с исходниками)
От: Гарин Георгий  
Дата: 25.01.02 09:12
Оценка:
Здравствуйте 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]: Перегрузка операций (дубль два с исходниками)
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 25.01.02 10:45
Оценка:
Здравствуйте Андрей Тарасевич, Вы писали:

АТ>Еще одно уточнение: оператор '+' не модифицирует своего левого операнда, поэтому соответствующий метод следует объявить как константный:


АТ>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]: Перегрузка операций (дубль два с исходниками)
От: Kaa Украина http://blog.meta.ua/users/kaa/
Дата: 25.01.02 10:49
Оценка:
Здравствуйте Kaa, Вы писали:
Kaa>А вот и нет

Отвечу себе-же А вот и да! Как-то расслабился. Все правильно: объект и есть левый операнд оператора )
Короче, повтоорил все то же другими словами. Сорри.
Алексей Кирдин
Re[4]: Перегрузка операций (дубль два с исходниками)
От: Андрей Тарасевич Беларусь  
Дата: 25.01.02 18:00
Оценка:
Здравствуйте Гарин Георгий, Вы писали:

АТ>>>"Лишние" вызовы конструкторов и деструкторов возникают в частности из за того, что ты передаешь объекты в оператор '+' по значению. Это приводит к созданиям промежуточных объектов-копий. Это совершенно не нужно. Предевать следует константные ссылки:


АТ>>>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]: Перегрузка операций (дубль два с исходниками)
От: Андрей Тарасевич Беларусь  
Дата: 25.01.02 18:04
Оценка:
Здравствуйте IAZ, Вы писали:

IAZ>И еще одно уточнеие в операторе '=' следует возвращать ссылку на текущий объект:


IAZ>polynom& polynom::operator=(const polynom&);


IAZ>и избавемся от еще одного временного объекта.


Согласен. Не заметил.
Best regards,
Андрей Тарасевич
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.